# TODO

  • [x] 编辑器插件文档
  • [x] vscode 插件合集Extension Pack
    • [x] https://code.visualstudio.com/blogs/2017/03/07/extension-pack-roundup
    • [x] https://code.visualstudio.com/api/references/extension-manifest#extension-packs
    • [ ] 更换思路,使用sync setting,这样可以同步配置和扩展,而且安全性高。难点:区分自己配置和团队配置
  • [x] 添加移动端调试工具
  • [ ] 通过monorepo方式整合npm包
    • [x] 安装npm包需要制定register到@yy:registry = "https://git.yeeyun.io/api/v4/packages/npm"
    • [x] gitlab没有package registry目录
    • [x] 提交信息时,使用scope区分包,feat(utils):添加工具库
    • [x] 通过gitlab boards添加计划
    • [x] 迁移私有库的包到gitlab
    • [ ] 添加@yy/cli,命令行工具
      • [ ] 快速生成模版页面
        • [x] cli编写流程https://juejin.cn/post/6977567286013984776#heading-3
        • [x] 详细介绍cli工具编写https://juejin.cn/post/6966119324478079007#heading-39
        • [x] sao相关:https://juejin.cn/post/6844904203102453774#heading-0
        • [x] create-vite解析:https://blog.csdn.net/qq_42049445/article/details/113752151
        • [x] ejs:生成模板
        • [ ] prompts:替代enquirer、inquirer,命令行询问问题
          • [ ] 校验
        • [ ] cac: 替代commander,完整的命令行解决方案
        • [ ] mri:替代minimist解析命令行及参数,速度更快,体积更小
        • [ ] download-git-repo:下载远程模板
        • [ ] prettier:格式化生成模板
        • [ ] kolorist:替代chalk,设置控制台输出输入输出颜色,
        • [ ] ora:控制台loading样式
        • [ ] fs-extra:生成文件包
        • [ ] cross-spawn:和execa差不多,但是下载量更多,包体积更小。支持跨平台调用系统命令
      • [ ] 压缩svg图片
    • [ ] 添加@yy/plugins,一般是对外部插件的引用和包装
      • [ ] 移动端调试工具eruda
      • [ ] 防止后退插件
      • [ ] 分享图片,两种方式比较
        • [ ] 使用html2canvas,代码体积小,但是加上图片的总体积比svg大
          • [ ] 流程,下载图片-压缩-编写海报-html2canvas-原生
          • [ ] 缺点:体积大
        • [ ] 使用svg,修改
          • [ ] 流程,下载svg-编写海报-svgo压缩-转换成base64-原生
          • [ ] 缺点:字体需要单独导入,中文文字在转换时需要特殊处理,不方便维护,基本不可以复用。
    • [ ] 添加@yy/utils,函数工具,校验函数(vue-use中如果有的则不添加)
    • [ ] 打包成umd和esm和commonjs,优先使用esm
  • [x] 前端规范文档
  • [ ] 组件 @yy/components
    • [ ] 文档
    • [ ] 基础组件
    • [ ] 业务组件
    • [ ] 区块
    • [ ] 支持主题切换
      • [ ] 实时预览
    • [ ] 只支持vue,方案:通过封装headlessui,手写样式的方式进行开发,搭配storybook来做文档和实时预览
      • [ ] 现在还没有搭建组件库的需求,直接使用headlessui
  • [ ] 前端构建
    • [ ] 前端项目打包留存版本
    • [ ] 现有项目切换vite
    • [x] 尝试vite

# ESLint

  1. 中英文符号限制

# bundle

  1. 推荐使用unbuild,支持特性:esm、cjs、ts及类型生成
  2. esbuild

# pnpm

  1. 通过husky检测是否有lock文件变动,有的话则自动执行pnpm install

    #!/usr/bin/env node
    # edit form https://github.com/abinavseelan/post-merge-install
    const { execSync } = require('child_process')
    const { resolve } = require('path')
    const chalk = require('chalk')
    const { dirname } = require('path')
    const PACKAGE_FILE = /pnpm-lock\.yaml/
    const getPackageFiles = (diffTree = '') =>
      diffTree.split('\n').filter((file) => PACKAGE_FILE.test(file))
    /**
     * Retuns unique list of items from an array
     * @param {Array} arr
     * @see https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_uniq
     */
    const unique = (arr) => (Array.isArray(arr) ? [...new Set(arr)] : [])
    /**
     * Given a list of file paths, returns the unique list of directories they are in.
     * @param {String[]}
     */
    const getDirectoriesToInstall = (files = []) =>
      Array.isArray(files) ? unique(files.map((file) => dirname(file))) : []
    ;(() => {
      const diffTree = execSync(
        'git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD'
      )
        .toString()
        .trim()
      const gitRoot = execSync('git rev-parse --show-toplevel').toString().trim()
      const changedPackageFiles = getPackageFiles(diffTree)
      const needsInstall = !process.env.CI && changedPackageFiles.length
      if (needsInstall) {
        console.log(
          chalk.yellow(`
    Detected changes in "${chalk.bold('pnpm-lock.yaml')}".
    Running "${chalk.bold('pnpm install')}" in the corresponding directories..\n`)
        )
        const directories = getDirectoriesToInstall(changedPackageFiles)
        try {
          for (const directory of directories) {
            const installDirectory = resolve(gitRoot, directory)
            console.log(
              chalk.yellow.dim(`${chalk.underline(installDirectory)}\n`)
            )
            execSync('pnpm install', {
              stdio: 'inherit',
              cwd: installDirectory,
            })
          }
        } catch (e) {}
      }
    })()
    

# monorepo

  1. 使用pnpm直接管理
  2. lerna,不再维护

# TypeScript

# 运行时

  1. 使用tsxesno也是它的别名, 底层使用esbuild
  2. ts-node,过时

# 类型声明

  1. JSDoc
  2. JSDoc+.d.ts
  3. 对于第三方包:DefinitelyTyped (opens new window)
  4. TS in JS 实践指北 (opens new window)

# DX(开发体验)

# 自动导入包

  1. 使用unplugin-auto-import

# JSDoc

# 介绍

# 注释

建议使用jsdoc的注释代替//,会带来更好的智能提示。

# @desc

描述字段,可以省略,也可以使用@description

# @see

相关链接

# @type

为后边的参数赋值相应type,还可以使用import语法加载其他文件

/**
 * @type { import ('./otherService') } // 这里用 type 指定 newObj 的类型
 */
var newObj = someRequireFn('./otherService')
newObj.a // 直跳到otherService.js的args.a
newObj.bar // 直跳到otherService.js的fn.bar

import还有其他用法,比如支持导入ts文件

# @example

用例提示

# @param

函数参数, 语法:@param {string} somebody Somebody's name ,依次为类型、名称、描述,类型和描述是可选的。通过定义@param参数可以为参数在上下文启用相关类型的方法,比如类型为string,则在输入该参数时会提示toStirng等原生方法。

对于对象参数的支持:

/**
 * @param {Object} options - The shape is the same as SpecialType above
 * @param {string} options.prop1
 * @param {number} options.prop2
 * @param {number} options.prop3
 * @param {number} [options.prop4]
 * @param {number} [options.prop5=42]
 */
function special(options) {
  return (options.prop4 || 1001) + options.prop5;
}

@params支持import语法导入外部类型:

/**
 * @param {import("element-ui/types/loading").LoadingServiceOptions} options
 */

# @typedef

为某一个对象参数赋类型

/**
 * ajax方法
 *
 * @example `ajax(options)`
 *
 * @typedef {Object} IAjaxOptions
 * @property {boolean} [jsonp] 是否jsonp
 * @property {boolean} [async] 是否async
 * @property {'GET'|'POST'} [methods] 请求方法
 * @property {(options: any)=>void} [success] 成功回调函数
 *
 * @param {IAjaxOptions} [options] 参数
 */
function ajaxNew (options) {}

# @property

@property的作用是声明@typedef类型里面包含的属性,用法和@param一致。

# typeof

通过使用typeof定义对象可以方便我们快速跳转到对象属性声明位置。

var foo = {
    a: 2,
    b: 2
}
/**
 * @param {typeof foo} obj
 */
function bar (obj) {
    obj.a // 「直跳」找到 foo 里定义的 a
}

# @returns

也可以写成@return

const args = {
    a: 1,
    b: 2
}
const fn = {
    foo: function () {},
    bar: function () {}
}
/**
 * 合并两个作用域
 *
 * @returns { typeof args & typeof fn } // 这里用 returns 指定了返回类型
 */
function someMergeFn (args, fn) {
    // ...
}
const newObj = someMergeFn(args, fn)
newObj.a // 直跳到上面 args.a
newObj.bar // 直跳到上面 fn.bar

不推荐使用以下这种方式,因为在引用函数时,返回值不会自动补全:

/**
 * @returns { Object } object
 * @returns { string } object.name
 */

# 已知问题

  1. 无法支持@private@protected这类 tag 修饰,表现在还是在提示中给了出来
  2. 无法直接对某个函数定义函数重载,需要依靠对象的形式
  3. 很多 tag 不支持,比如@augments@mixin等,官网给的例子不能在 VSCode 编辑器里展现出来预期的效果

# vue

# react

# prettier介绍

如果有多个层级目录的prettier配置文件,那么会采取就近原则,如果当前目录没有配置文件,则会去查找父级目录,以此类推。

# stylelint介绍

如果有多个层级目录的stylelint配置文件,那么会采取就近原则,如果当前目录没有配置文件,则会去查找父级目录,以此类推。v14后stylelint只支持csspostcss,lessscss需要添加单独的解析器:

"overrides": [
    {
      "files": ["**/*.scss"],
      "customSyntax": "postcss-scss"
    }
  ],

# 与browserlist配合

安装插件stylelint-no-unsupported-browser-features,会对不兼容的目标浏览器进行错误提示。该插件底层使用doiuse

# 问题

# 如何单独为某种后缀名文件添加规则?

比如scss文件添加一个特定规则,那么只需要在配置中添加overrides选项进行单独配置即可:

"overrides": [
    {
      "files": ["**/*.scss"],
      "rules": {
        "string-quotes": "single"
      }
    }
  ]

# 代码覆盖率

istanbul.js,阿里有一种方案可以通过代码覆盖率自动把没有执行到的代码拆分成动态导入:https://mp.weixin.qq.com/s/iQy-Y7yxla3HItKjsNTwng

# vscode

添加formatOnSave,省去手动格式化,并且防止遗忘格式化导致无用的历史记录,缺点是容易在自动格式化时修改原代码

"editor.formatOnSave": true,

# git 规范和 Changelog 生成

良好的 Git commit 规范优势:

  • 加快 Code Review 的流程
  • 根据 Git Commit 的元数据生成 Changelog
  • 后续维护者可以知道 Feature 被修改的原因

技术方案
20191004115054.png
提交格式要求

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

type 代表某次提交的类型,比如是修复一个 bug 还是增加一个新的 feature.所有的 type 类型如下:

  • build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
  • ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle 等)的提交,
  • docs:仅仅修改了文档,比如 README,CHANGELOG,CONTRIBUTE 等等
  • feat:新增 feature
  • fix:修复 bug
  • pref:优化相关,比如提升性能、体验
  • refactor:代码重构,没有加新功能或者修复 bug
  • revert:回滚到上一个版本
  • style:仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑
  • test:测试用例,包括单元测试、集成测试等
  • chore:不属于以上类型的其他类型

安装:
npm install husky --save-dev
npm install --save-dev @commitlint/{cli,config-conventional}
根目录创建配置文件:

// commitlint.config.js
module.exports = { extends: ["@commitlint/config-conventional"] };

package.json中添加包依赖和触发时机

"lint-staged": {
    "*.{js,vue}": ["eslint","git add"],
    "*.{css,vue}": ["stylelint","git add"]
  },
"husky": {
  "hooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
},
"devDependencies": {
  "@commitlint/cli": "^9.1.2",
  "@commitlint/config-conventional": "^9.1.2",
  "husky": "^4.2.5",
  "lint-staged": "^10.2.11"
}

# prettier和eslint冲突问题?

禁用 ESLint中和Prettier配置有冲突的规则;再使用 Prettier 来替代 ESLint 的格式化功能; 安装eslint-config-prettier插件配置集,把其配置到eslintrc规则的尾部。执行ESLint命令,会禁用那些和Prettier配置有冲突的规则。 安装eslint-plugin-prettier插件,先使用Prettier对代码进行格式化,再并对不一致的地方进行标记; 这两个包配合使用,可以达到运行 eslint --fix 时,采用Prettier的配置规则 来格式化文件。

参考:https://juejin.cn/post/6895889063111294990

# 环境变量与模式

构建项目的时候我们可能需要多个环境,比如生产、预发布、测试,这个时候我们可以通过.env环境变量文件配合指令中的MODE变量来实现,例如:

指令:

corss-env MODE=test nuxi dev 

添加env文件:.env.test