NodeJS
首发于NodeJS
Egg 支持 JS 智能提示

Egg 支持 JS 智能提示

## 先睹为快

感受下在 JS 下也能 智能提示点击跳转 的 Feeling~

  • 在绝大部分地方都可以提示自动挂载的对象。
  • 通过CMD + Click 可以跳转到对应的源码。
  • 自动关联 JSDoc

Try it out~

# 通过骨架初始化
$ mkdir showcase && cd showcase
$ npm init egg --type=simple

# 安装依赖,并启动
$ npm i --no-package-lock
$ npm run dev

## 背景

VSCode 等 IDE 的智能提示,一般是通过静态分析来实现的。

因此,它们对 Egg 的支持并不是很好,因为 Egg 是通过 Loader 动态挂载的。

幸好,Egg 团队依旧一如既往的关注研发体验。在不懈的努力研究下,We made it!

我们此前已经支持了 TS:『当 Egg 遇到 TypeScript,收获茶叶蛋一枚』。

而这次,我们对 JS 的项目,也提供了类似的支持,保持一致的研发体验。


## 写在展开之前

尽管我们对 JS 和 TS 的 Egg 项目,都支持了智能提示和跳转的支持。

但我们还是期望你能对它保持一个理性的认知:

Egg 研发委提示您:
代码千万行,测试要写完。
提示不过脑,上线泪两行。

请务必提醒自己:智能提示仅仅是锦上添花,而不是不可或缺的。

对于业务而言,TS 并不是银弹,完善的单元测试覆盖,严谨的 Code Review 流程更重要。


## 解决思路

主要思路其实非常简单,无非就是:

动态生成 d.ts ,使用 TypeScript 的 Declaration Merging 特性,并读取 JSDoc 注释。

egg-ts-helper 已经对 TS 和 JS 都提供了同样的支持,并内置到 egg-bin 中。

需要注意的是,为了更好的体验,开发者需要完善应用本身的 JSDoc


## 旧项目升级

非常简单,只需要几步:

  • 删除 node_modules 重新安装依赖(不要锁版本),升级到最新的 egg-bin
  • 修改 package.json 添加 "egg": { "declarations": true }
  • 启动应用 npm run dev
    • egg-bin 会自动生成对应的 d.ts
    • 如果无法提示,可能是 VSCode 缓存,需重启一次。
  • 开始体验吧!

## 注意事项

限于语言特性,并不敢说尽善尽美,但至少解决了有无问题,大部分的体验还 OK。

### Router

需增加 JSDoc 定义:

// app/router.js

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
  const { router, controller } = app;
  router.get('/', app.middleware.access(), controller.home.index);
};

### Config

格式需修改如下:

// config/config.default.js
/* eslint valid-jsdoc: "off" */

/**
 * @param {Egg.EggAppInfo} appInfo - { baseDir, root, env, ... }
 */
module.exports = appInfo => {
  /**
   * 框架内置配置
   * @type {Egg.EggAppConfig}
   */
  const config = {};
  config.keys = appInfo.name + '_1543991101115_6311';
  config.middleware = [];

  /**
   * 自定义配置
   */
  const userConfig = {
    query: {
      /**
       * default query count
       */
      limit: 10,
    },
    biz: {
      test: '123',
    },
  };

  return {
    ...config,
    ...userConfig,
  };
};

### Service

主要是 JSDoc

// app/service/user.js

const { Service } = require('egg');

class UserService extends Service {
  /**
   * @typedef {Object} User - user class
   * @property {String} name - name
   */

  /**
   * list users with filter
   * @param {String} [keyword] - user name filter
   * @param {Number} [limit] - fetch count
   * @return {Array<User>} return required users
   */
  async list(keyword, limit) {
    return [].filter(item => item.name.includes(keyword)).slice(limit);
  }
}

module.exports = UserService;

### Plugin

// config/plugin.js

/** @type Egg.EggPlugin */
module.exports = {
  nunjucks: {
    enable: true,
    package: 'egg-view-nunjucks',
  }
};

## 写在最后

我们依旧一如既往的关注研发体验,后续会有更多优化。

预告:春节期间,我们闭关把文档重新梳理了信息架构,精简合并了不少内容,从用户角度去重新阐述,不过由于工作量较大,还需要耐心等待。
编辑于 2019-02-18

文章被以下专栏收录

    在 eggjs 团队的日常协作中,遵循「基于 GitLab 的硬盘式异步协作模式」。 先通过 issue 发起 RFC 召集讨论,再提交 Pull Request 和 Code Review,这样便于沉淀,即使是当时没有参与讨论的开发者,事后也能通过 issue 了解某个功能设计的前因后果。 因此,本专栏用于汇总近期值得关注的 Egg.js 和 Node.js 相关动态,将不定期发布。