一、概念

命令行界面(英语:command-line interface,缩写:CLI),俗称脚手架。

1、基本工作流程

  • 通过命令行交互询问用户问题
  • 根据用户回答的结果生成文件

    2、热门工具

    | 名称 | 简介 | | —- | —- | | commander | 命令行自定义指令 | | inquirer | 命令行询问用户问题,记录回答结果 | | chalk | 控制台输出内容样式美化 | | ora | 控制台 loading 样式 | | figlet | 控制台打印 logo | | easy-table | 控制台输出表格 | | download-git-repo | 下载远程模版 | | fs-extra | 系统fs模块的扩展,提供了更多便利的 API,并继承了fs模块的 API | | cross-spawn | 支持跨平台调用系统上的命令 |

二、vue/cli 配置

1、初始化

  • 通过npx
    • 执行:npx @vue/cli create my-project

2、配置选择

  • default 配置
    • Babel:即ESNext,可使用下一代 JavaScript 语法。作为 webpack loader加载
    • Eslint:即代码格式检测
  • 手动选择特性:可以选择将已选项保存为一个将来可复用的 preset。

    • ~/.vuerc:被保存的 preset 将会存在用户的 home 目录下一个名为 .vuerc 的 JSON 文件里。如果你想要修改被保存的 preset / 选项,可以编辑这个文件

      3、系统组件

  • CLI 服务 (@vue/cli-service) 是一个开发环境依赖。局部安装在每个 @vue/cli 创建的项目中的一个 npm 包

    • 构建于 webpack 和 webpack-dev-server 之上
  • CLI 插件是提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。Vue CLI 插件的名字以 @vue/cli-plugin- (内建插件) 或 vue-cli-plugin- (社区插件) 开头
  • 项目内部运行 vue-cli-service 命令时,它会自动解析并加载 package.json 中列出的所有 CLI 插件

4、插件

插件可以修改 webpack 的内部配置,也可以向 vue-cli-service 注入命令。每个 CLI 插件包含一个 (用来创建文件的) 生成器和一个 (用来调整 webpack 核心配置和注入命令的) 运行时插件

  • 已有项目中安装一个插件:使用 vue add 命令,如 vue add eslint
    • 建议先提交项目最新状态,该命令可能调用插件的文件生成器并很有可能更改你现有的文件
    • 不带 @vue 前缀,该命令会换作解析一个 unscoped 的包,会安装第三方插件
    • 插件已经被安装:使用 vue invoke 命令跳过安装过程,只调用它的生成器
  • 本地插件:需要每个文件暴露一个函数,接受插件 API 作为第一个参数

    1. {
    2. "vuePlugins": {
    3. "service": ["my-commands.js"]
    4. }
    5. }

    5、cli服务

  • vue-cli-service serve :启动一个开发服务器 (基于 webpack-dev-server) 并附带开箱即用的模块热重载 (Hot-Module-Replacement)。也可使用 vue.config.js 里的 devServer 字段配置开发服务器

  • vue-cli-service build [options]:在 dist/ 目录产生一个可用于生产环境的包,带有 JS/CSS/HTML 的压缩,和为更好的缓存自动的 vendor chunk splitting。它的 chunk manifest 会内联在 HTML 里
    • vue-cli-service build —modern:产生两个应用的版本,一个现代版的包,面向支持 ES modules 的现代浏览器,另一个旧版的包,面向不支持的旧浏览器。 ``` 用法:vue-cli-service build [options] [entry|pattern]

选项: —modern 面向现代浏览器带自动回退地构建应用 —target app | lib | wc | wc-async (默认值:app) 允许你将项目中的任何组件以一个库或 Web Components 组件的方式进行构建 —report 生成 report.html 以帮助分析包内容 —report-json 生成 report.json 以帮助分析包内容

  1. - `vue-cli-service inspect`:审查一个 Vue CLI 项目的 webpack config
  2. <a name="irOLy"></a>
  3. ### 6、浏览器兼容性
  4. <a name="lwT8l"></a>
  5. #### 6.1 browserslist
  6. `package.json` 文件里的 `browserslist` 字段指定项目的目标浏览器的范围。值会被 @babel/preset-env Autoprefixer 用来确定需转译的 JS 特性和需添加的 CSS 浏览器前缀。如何指定见[browserslist](https://github.com/browserslist/browserslist)
  7. <a name="dBP5Y"></a>
  8. #### 6.2 polyfill
  9. 一个默认的 Vue CLI 项目会使用 @vue/babel-preset-app,它通过 `@babel/preset-env` `browserslist` 配置来决定项目需要的 polyfill
  10. - 默认把 `useBuiltIns: 'usage'` 传递给 `@babel/preset-env`,根据源代码中出现的语言特性自动检测需要的 polyfill。确保最终包里 polyfill 数量的最小化。但**如果其中一个依赖需要特殊的 polyfill,默认情况下 Babel 无法将其检测出来**
  11. - 如果有依赖需要 polyfill
  12. - **如果该依赖基于一个目标环境不支持的 ES 版本撰写:** 将其添加到 `vue.config.js` 中的 `transpileDependencies` 选项。这会为该依赖同时开启语法转换和根据使用情况检测 polyfill
  13. - **如果该依赖交付了 ES5 代码并显式地列出了需要的 polyfill:** 使用 `@vue/babel-preset-app` polyfills 选项预包含所需要的 polyfill。**注意 **`**es.promise**`** 将被默认包含,因为现在的库依赖 Promise很普遍。**
  14. ```javascript
  15. // babel.config.js
  16. module.exports = {
  17. presets: [
  18. ['@vue/app', {
  19. polyfills: [
  20. 'es.promise',
  21. 'es.symbol'
  22. ]
  23. }]
  24. ]
  25. }
  • 如果该依赖交付 ES5 代码,但使用 ES6+ 特性且没有显式地列出需要的 polyfill (例如 Vuetify):请使用 **useBuiltIns: 'entry'** 然后在入口文件添加 **import 'core-js/stable'; import 'regenerator-runtime/runtime';**。这会根据 **browserslist** 目标导入所有 polyfill,但是因为包含了一些没有用到的 polyfill 所以最终的包大小可能会增加。
    • 构建库或是 Web Component 时的 Polyfills:推荐给 @vue/babel-preset-app 传入 useBuiltIns: false 选项。确保库或是组件不包含不必要的 polyfills。通常来说,打包 polyfills 应当是最终使用你的库的应用的责任

7、webpack 相关

7.1 简单的配置方式

  • configureWebpack 作为对象:将会被 webpack-merge 合并入最终的 webpack 配置

    1. // vue.config.js
    2. module.exports = {
    3. configureWebpack: {
    4. plugins: [
    5. new MyAwesomeWebpackPlugin()
    6. ]
    7. }
    8. }
  • configureWebpack 作为函数:基于环境有条件地配置行为或直接修改配置,在环境变量被设置后懒执行

    • 函数第一个参数会收到已经解析好的配置config。在函数内可直接修改配置,或返回一个将会被合并的对象
      1. // vue.config.js
      2. module.exports = {
      3. configureWebpack: config => {
      4. if (process.env.NODE_ENV === 'production') {
      5. // 为生产环境修改配置...
      6. } else {
      7. // 为开发环境修改配置...
      8. }
      9. }
      10. }

7.2 链式操作

  • webpack-chain 库提供一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则和具名插件,并有机会在后期进入这些规则并对它们的选项进行修改。允许更细粒度的控制其内部配置

    1. // vue.config.js
    2. module.exports = {
    3. chainWebpack: config => {
    4. config.module
    5. .rule('vue')
    6. .use('vue-loader')
    7. .loader('vue-loader')
    8. .tap(options => {
    9. // 修改它的选项...
    10. return options
    11. })
    12. config.module
    13. .rule('graphql')
    14. .test(/\.graphql$/)
    15. .use('graphql-tag/loader')
    16. .loader('graphql-tag/loader')
    17. .end()
    18. // 你还可以再添加一个 loader
    19. .use('other-loader')
    20. .loader('other-loader')
    21. .end()
    22. const svgRule = config.module.rule('svg')
    23. svgRule.uses.clear()//清除已有的所有 loader。否则接下来 loader 会附加在该规则现有 loader 后
    24. // 添加要替换的 loader
    25. svgRule
    26. .use('vue-svg-loader')
    27. .loader('vue-svg-loader')
    28. config.plugin('html')
    29. .tap(args => {
    30. //传递给 html-webpack-plugin's 构造函数的新参数
    31. args[0].template = '/Users/username/proj/app/templates/index.html'
    32. return args
    33. })
    34. }
    35. }

8、多页面打包

多页面:指一个项目多个入口,打包会生成多个html文件,实际开发过程混合在一个项目中开发

在 multi-page 模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。其值应该是一个对象,对象的 key 是入口的名字,value 是:

  • 一个指定了 entry, template, filename, titlechunks 的对象 (除了 entry 之外都是可选的);
  • 或一个指定其 entry 的字符串。
    1. module.exports = {
    2. pages: {
    3. index: {
    4. // page 的入口
    5. entry: 'src/index/main.js',
    6. // 模板来源
    7. template: 'public/index.html',
    8. // 在 dist/index.html 的输出
    9. filename: 'index.html',
    10. // 当使用 title 选项时,
    11. // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
    12. title: 'Index Page',
    13. // 在这个页面中包含的块,默认情况下会包含
    14. // 提取出来的通用 chunk 和 vendor chunk。
    15. chunks: ['chunk-vendors', 'chunk-common', 'index']
    16. },
    17. // 当使用只有入口的字符串格式时,
    18. // 模板会被推导为 `public/subpage.html`
    19. // 并且如果找不到的话,就回退到 `public/index.html`。
    20. // 输出文件名会被推导为 `subpage.html`。
    21. subpage: 'src/subpage/main.js'
    22. }
    23. }

三、create-react-app 配置

1、初始化

创建一个名为 ts-react 的 typescript 项目

  • npx:npx create-react-app ts-react --template typescript

2、tsconfig.json解读

通常 tsconfig.json 文件主要包含两部分内容:指定待编译文件定义编译选项。compilerOptions 属性作用是配置编译选项

  1. {
  2. "compilerOptions": {
  3. "target": "es5", // 目标语言的版本
  4. "lib": [
  5. "dom",
  6. "dom.iterable",
  7. "esnext"
  8. ], // TS需要引用的库,即声明文件
  9. "allowJs": true, // 允许编译器编译JSJSX文件
  10. "skipLibCheck": true, // 忽略所有的声明文件(*.d.ts)的类型检查
  11. "esModuleInterop": true, // 允许export=导出,由import from 导入
  12. "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
  13. "strict": true,
  14. "forceConsistentCasingInFileNames": true, // 禁止对同一个文件的不一致的引用
  15. "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即无break语句后面不会执行)
  16. "module": "esnext", // 指定生成代码的模板标准
  17. "moduleResolution": "node", // 使用哪种模块解析策略
  18. "resolveJsonModule": true, // 是否可以导入 JSON 模块
  19. "isolatedModules": true, // 将每个文件作为单独的模块
  20. "noEmit": true, // 不生成输出文件
  21. "jsx": "react-jsx" // .tsx文件里支持JSX "React" "Preserve"
  22. },
  23. "include": [
  24. "src"
  25. ]
  26. }

3、自定义配置

弹出cra配置,仅能弹出一次:npm run eject

4、react-scripts

  • cra项目中的开发依赖项。可运行内置命令行

5、代码规范、Git工作流/提交规范

  • 代码格式化工具:prettier
    • 安装prettier:yarn add prettier -D
    • 配置.prettierrc ```json { “trailingComma”: “es5”, // 在任何可能的多行中,添加es5中被支持的尾逗号,默认none “tabWidth”: 4, // 水平缩进的空格数,默认为 2 “singleQuote”: true, // 是否使用单引号 “jsxBracketSameLine”: false, // 是否多属性html标签的‘>’折行放置 “printWidth”: 100, // 指定代码换行的行长度,超过最大值换行 }
  1. - 代码规范校验工具:**eslint**
  2. - Git工作流规范:
  3. - **husky**:git hooks工具
  4. - 安装:`yarn add husky -D`
  5. - 配置:在package.json 文件的scripts配置项添加命令
  6. ```json
  7. "scripts": {
  8. "prepare": "husky install"
  9. }
  1. - 执行:`yarn prepare`,创建.husky/目录并指定该目录为git hooks所在的目录
  • lint-staged : pre-commit Hook 脚本,允许我们在 git 中的暂存文件上运行脚本

    • 安装:yarn add lint-staged -D
    • 配置:
      1. "lint-staged": {
      2. "src/**/*.{js,jsx,ts,tsx,json}": [
      3. "prettier --write",
      4. "eslint",
      5. "git add"
      6. ]
      7. }
  • pretty-quick

    • 安装:yarn add pretty-quick -D
  • commitlint commit-msg Hook脚本,帮助我们在多人开发时,遵守 git 提交约定

    • 安装:yarn add @commitlint/cli @commitlint/config-conventional -D
    • 配置:在根目录src目录下创建 commitlint.config.js 文件
      1. module.exports = {
      2. extends: [
      3. "@commitlint/config-conventional"
      4. ],
      5. // 自定义规则,可不填写
      6. rules: {
      7. 'type-enum': [
      8. 2,
      9. 'always',
      10. [
      11. 'bug', // 此项特别针对bug号,用于向测试反馈bug列表的bug修改情况
      12. 'feat', // 新功能(feature)
      13. 'fix', // 修补bug
      14. 'docs', // 文档(documentation)
      15. 'style', // 格式(不影响代码运行的变动)
      16. 'refactor', // 重构(即不是新增功能,也不是修改bug的代码变动)
      17. 'test', // 增加测试
      18. 'chore', // 构建过程或辅助工具的变动
      19. 'revert', // 撤销之前的commit
      20. 'merge' // 合并分支
      21. ]
      22. ]
      23. }
      24. };
  • 添加钩子: 首先,运行 yarn prepare

    • commit-msg :
      • npx husky add .husky/commit-msg "yarn commitlint --edit '$1'"
    • pre-commit: 二选一
      • npx husky add .husky/pre-commit "yarn lint-staged --allow-empty '$1'"
      • npx husky add .husky/pre-commit "yarn pretty-quick --staged"
  • 添加钩子到git中去:
    • 添加 commit-msg 到git中去:git add .husky/commit-msg
    • 添加 pre-commit 到git中去:git add .husky/pre-commit
      • Git提交规范:commitizen
  • 安装:yarn add commitizen cz-conventional-changelog -D
  • 配置:在package.json中加入以下代码。其中,需要增加一个script,使得我们可以通过执行npm run cm来代替git commit,而path为cz-conventional-changelog包相对于项目根目录的路径
    1. {
    2. "scripts": {
    3. "commit": "git-cz",
    4. },
    5. "config": {
    6. "commitizen": {
    7. "path": "node_modules/cz-conventional-changelog"
    8. }
    9. }
    10. }
  • 自动化版本控制:standard-version 升级版本号、生成 changelog 及 tag

    • 安装:yarn add standard-version -D
    • package.json中增加配置:

      1. "scripts": {
      2. "release": "standard-version"
      3. }
    • 执行:先 yarn commit,再yarn release

      6、添加代理

要告知开发服务器在开发中,将任何未知请求代理到您的 API 服务器,在 package.json 中添加一个代理字段:
"proxy": "http://localhost:4000"

7、source-map-explorer 分析包大小

  • 安装:yarn add source-map-explorer
    • package.json配置加上脚本: ```json “scripts”: {
  • “analyze”: “source-map-explorer ‘build/static/js/*.js’”, “start”: “react-scripts start”, “build”: “react-scripts build”, “test”: “react-scripts test” }

    1. - 执行:
    2. ```powershell
    3. npm run build
    4. npm run analyze
  • 不安装:npx source-map-explorer build/static/js/*.js

参考资料