# webpack5-cli脚手架

# 依赖安装

// 安装webpack相关
// Html-webpack-plugin: 从模板生成一个HTML文件
// webpack-merge:合并配置项
// webpack-dev-server: 开发模式,启动一个本地服务
npm i webpack webpack-cli webpack-dev-server  html-webpack-plugin webpack-merge --save-dev

// 清理out目录
npm i clean-webpack-plugin --save-dev
// 样式:css、scss、less
npm i style-loader css-loader sass-loader sass less less-loader --save-dev
// 抽取css
npm i mini-css-extract-plugin --save-dev
// css压缩:webpack4使用'optimize-css-assets-webpack-plugin'
// npm install css-minimizer-webpack-plugin --save-dev

// 处理css样式(背景图url、字体资源url),添加css前缀:autoprefixer用于给css加前缀, cssnano用于压缩优化css
npm i postcss-loader postcss autoprefixer cssnano --save-dev

// 打包进度条
npm i webpackbar --save-dev

// 跨平台,环境变量:process.env
npm i cross-env --save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// old
"webpack": "^5.48.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
 
// new
"webpack": "^5.51.1",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.1.0",
1
2
3
4
5
6
7
8
9

注意:使用的webpack-dev-server版本是v4,从v3到v4的升级文档,参考这里 (opens new window)

问题:webpack-dev-server v3版本与webpack5搭配时,overlay选项的message显示不正确。更新到v4后显示正常。

webpack-dev-server v3版本,eslint校验出现error时,overlay信息:

image-20210901092934213

升级到v4版本,显示正常:

image-20210901093347913

# 热更新

开发环境热更新,需要设置devServerhot为true,同时配合使用webpack.HotModuleReplacementPlugin (opens new window)才能完全启用HMR。

module.exports = {
  devServer: {
    hot: true
  },
  plugins: [
        // enable HMR with hot:true
        new webpack.HotModuleReplacementPlugin({})
  ],
}
1
2
3
4
5
6
7
8
9

注意,如果项目中配置了.browserslistrc文件,会导致热更新失效。此时需要显示的指定构建目标target

module.exports = {
  target: "web",// 防止与".browserslistrc" 冲突导致热更新失效
  devServer: {
    hot: true
  },
  plugins: [
        // enable HMR with hot:true
        new webpack.HotModuleReplacementPlugin({})
  ],
}
1
2
3
4
5
6
7
8
9
10

# babel配置

babel配置文件可以是.babelrc文件,或者 babe.config.js,配置文件名可参考这里Config Files (opens new window)

npm i @babel/core @babel/cli @babel/preset-env babel-loader --save-dev
1

.babel.config.js配置如下

module.exports = {
    presets:[
        [
            "@babel/preset-env", // preset的配置项
        ]
    ]
}
1
2
3
4
5
6
7

# react支持

针对react,需安装@babel/preset-env@babel/preset-react

npm i @babel/preset-react --save-dev

npm i react react-dom --save
1
2
3

同时在.babel.config.js中添加如下配置:

module.exports = {
    presets:[
        "@babel/preset-env",  // js预设
      	'@babel/preset-react', // react
    ]
}
1
2
3
4
5
6

# vue支持

vue中jsx支持

针对vuejsx,需额外安装插件才支持:

npm i vue --save
npm i vue-loader  --save-dev

// vue2
npm i vue-template-compiler --save-dev

// 如果是vue3
// npm i @vue/compiler-sfc --save

// vue中支持jsx
npm i @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props --save-dev
1
2
3
4
5
6
7
8
9
10
11

同时在.babel.config.js配置文件中添加配置以启用vue-jsx支持:

module.exports = {
  presets: [
    "@babel/preset-env",  // js预设
    // '@babel/preset-react', // react
    '@vue/babel-preset-jsx' // vue jsx
	],
}
1
2
3
4
5
6
7

.vue文件解析

为了解析.vue文件,需要在webpack.dev.config中配置对应的loader:

let VueLoaderPlugin = require('vue-loader/lib/plugin');
let appSrc = path.resolve(__dirnam, './src');
module.exports = {
  resolve: {
        modules: [appSrc, 'node_modules'],
        // 缺少ts, tsx支持
        extensions: ['.js', '.jsx', '.json', '.vue', '.css', '.scss', '.less'],
        alias: {
            '@': appSrc,
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                use: ['vue-loader']
            }
        ]
   },
  plugins: [
       new VueLoaderPlugin()
   ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# @babel/preset-env

需要配置@babel/preset-env插件选项,参考options选项 (opens new window)

# modules

如果需要启用tree-shakingbable.config.js中需要关闭模块转换 (opens new window)功能。

module.exports = {
    presets:[
        [
            "@babel/preset-env",
            {
                // "useBuiltIns": "usage",
                "loose": false,
                "modules": false, // 关闭模块转换,目的是为了启用es6的tree-shaking
            }
        ],
    ],
    // https://babeljs.io/docs/en/assumptions
    // "assumptions": {
    //     "noClassCalls": true
    // },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# loose

宽松模式,默认为false,主要作用是:将class类转换为es5代码后,构造函数需要进行this检查。即只能通过new的方式使用构造函数。

class Game {
    name = 'Violin Charades'
}
const myGame = new Game();
1
2
3
4

默认情况下(loose为false),转换后的代码为:

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

// hello.js
var Game = function Game() {
  // this检查,Game只能作为构造函数使用(即new操作符)
  _classCallCheck(this, Game);

  _defineProperty(this, "name", 'Violin Charades');
};

var myGame = new Game();
1
2
3
4
5
6
7
8
9
10
11
12
13

其他情况下(loose为true),转换后的代码为:

var Game = function Game() {
  // 不做this检查,Game可以作为普通函数调用
  this.name = 'Violin Charades';
};

var myGame = new Game();
1
2
3
4
5
6

需要注意的是:自Babel 7.13,建议使用顶级选项配置 assumptions (opens new window), 来配置loose相关。

module.exports = {
    presets:[
        [
            "@babel/preset-env",
            {
                "loose": false
            }
        ],
    ],
    // https://babeljs.io/docs/en/assumptions
    // "assumptions": {
    //      "noClassCalls": true
    // },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# useBuiltIns

可参考babeljstry it out (opens new window),在线查看转换结果。

useBuiltIns: 该选项主要用于配置@babel/preset-env如何处理polyfills,包括entryusagefalse3个值。

  • entry:入口处全部引入
  • usage:按需引用
  • false:不引入
# entry

业务代码中全量引入:

import 'core-js/stable'
import 'regenerator-runtime/runtime'
1
2
# usage按需引入

方式1:配合corejs选项

@babel/polyfill自7.4.0之后就过时了,建议使用core-js,并配合corejs选项来配置

安装core-js:

npm i core-js@3 --save
# or
// npm i core-js@2 --save
1
2
3

配置时要注意: 建议指定次要版本,否则 "3" 将被理解为 "3.0"版本,它可能不包括你需要的feature

module.exports = {
    presets:[
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "core-js:": { version: "3.16", proposals: true },
            }
        ]
    ]
}
1
2
3
4
5
6
7
8
9
10
11

方式2:@babel/plugin-transform-runtime插件,配合@babel/runtime

@babel/plugin-transform-runtime (opens new window)配合@babel/runtime (opens new window),在编写library库的时候,推荐使用。可参考官方文档 (opens new window)

关于@babel/runtime的介绍,也可以参考这篇文章 (opens new window)

@babel/plugin-transform-runtime: 其主要作用就是,复用babel inject出来的公共函数。默认情况下,是在使用的地方inject出来代码。配置该插件后,则换成从统一的入口引入。

npm i @babel/runtime @babel/runtime-corejs3 --save
// @babel/plugin-transform-runtime配置corejs时,需要安装@babel/runtime-corejs3

npm i @babel/plugin-transform-runtime --save-dev
1
2
3
4

配置如下:

module.exports = {
    presets:[
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "core-js:": { version: "3.16", proposals: true },
            }
        ]
    ],
    plugins: [
        [ 	// polyfill方案1升级,目的是复用babel的helper函数
            "@babel/plugin-transform-runtime", 
            {
                "corejs": 3
            }
        ]
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

举例说明:

可使用babeljs的在线编译 (opens new window),查看结果

// 1.js
class Person{}
1
2

当我们采用方式1时,babel编译结果如下:

"use strict";

function _classCallCheck(instance, Constructor) { 
  if (!(instance instanceof Constructor)) { 
    throw new TypeError("Cannot call a class as a function"); 
  } 
}

var Person = function Person() {
  _classCallCheck(this, Person);
};

1
2
3
4
5
6
7
8
9
10
11
12

当我们采用方式2时,babel编译结果为:

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var Person = function Person() {
  (0, _classCallCheck2["default"])(this, Person);
}; 
1
2
3
4
5
6
7

我们会发现:

1、方式2复用了_classCallCheck这个方法,换成了从@babel/runtime中引入。这样,即使有100个js文件,_classCallCheck也只会有一份。

2、方式1则是直接将代码拷贝到了页面中。如果有100个js文件,则会产生100个_classCallCheck函数。

# browserslist

Browsersllist (opens new window): 作用是在babel转义时,根据配置判断需要引入哪些polyfill。

可以配置.browserslist文件或者babe.config.js中配置targets属性。

优点:高版本浏览器(或者非IE环境下),很多代码不需要进行polyfill,可以大幅度减小代码输出体积。

安装:

npm i browserslist --save
1

配置.browserslist文件

> 0.2%
Firefox ESR
not IE 11
1
2
3

或者在babel.config.js中配置targets属性

module.exports = {
		// 对象方式
    // targets: {
    //     "chrome": "65",
    //     "firefox": "",
    //     // "ie": 11,
    // },
    // 字符串格式
    // targets: '> 0.5%, last 2 versions, Firefox ESR, not dead, not IE 11',
}
1
2
3
4
5
6
7
8
9
10

配置完成后,即可在命令行中执行npx browserslist查看支持的浏览器结果:

# 参考

# plugins

# CopyWebpackPlugin

用于文件拷贝,安装:

npm install copy-webpack-plugin --save-dev
1

使用:

const CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        { from: "source", to: "dest" },
        { from: "other", to: "public" },
      ],
    }),
  ],
};
1
2
3
4
5
6
7
8
9
10
11
12

# ESLintWebpackPlugin

主要用于开发环境/生成环境检查代码规范。

webpack5之后,eslint-loader已经被弃用,推荐使用eslint-webpack-plugin. (opens new window),中文文档在这里 (opens new window)

安装插件:

npm install eslint-webpack-plugin --save-dev
1

配置插件:

const ESLintWebpackPlugin = require('eslint-webpack-plugin');
module.exports = {
  // elinst校验,替代旧的eslint-loader
  new ESLintPlugin({
  	exclude: ['node_modules'],
    files: ['.', 'src', 'config'],
    formatter: 'table',
    // extensions: ['js', 'jsx'],
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'], // 添加对.vue的校验,默认只支持js后缀
    emitError: true, // 发射错误信息
    emitWarning: true, // 发射告警信息
    // 只有在mode为'production'时,当出现eslint错误时,构建才会fail。
    // https://github.com/webpack-contrib/eslint-webpack-plugin/issues/51#issuecomment-768213066
    failOnError: true, // 默认true,出现eslint error的时候,构建fail。
    // failOnWarning: true, // 默认false,出现eslint warning的时候,构建fail。
}),
  // ...
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

注意:

只有当webpack的modeproduction时,同时配置failOnErrortrue时,如果出现eslint error,webpack才能阻止构建。否则,eslint虽然会校验错误,但是不影响正常的构建打包过程。

eslint校验失败后,message中文乱码问题

升级webpack-dev-server到v4版本即可

# terser-webpack-plugin

用于覆盖webpack中关于terser-webpack-plugin的默认配置。

安装:

// 注意:webpack5及以上,内部自带该插件,不需要再安装
npm install terser-webpack-plugin --save-dev
1
2

配置:

module.exports = {
    optimization: {
        concatenateModules: true,//开启scope-hoisting
        minimize: true, // 开启webpack压缩
        minimizer: [  // 自定义TerserWebpackPlugin实例配置
          new TerserWebpackPlugin({
            parallel: true,/** 开启多进程并行压缩 */
            // test: /\.js(\?.*)?$/i, // 压缩js文件
            extractComments: false, // 不抽取注释
          })
        ],
     },
};
1
2
3
4
5
6
7
8
9
10
11
12
13

# DefinePlugin (opens new window) vs EnvironmentPlugin (opens new window)

DefinePlugin

module.exports = {
  plugins: [
        // 环境变量:DefinePlugin vs EnvironmentPlugin
        new webpack.DefinePlugin({
            "process.env.debug": true,
            "process.env.test": JSON.stringify("test"),
            "PRODUCTION": JSON.stringify(true), // bool值
          	"VERSION": JSON.stringify('v1'), // 字符串
        })
    ],
}
1
2
3
4
5
6
7
8
9
10
11

index.js输出:

console.log("process.env.debug", process.env.debug); // true, 布尔值
console.log("process.env.test", process.env.test); // "test",字符串
console.log("PRODUCTION", PRODUCTION); // true,布尔值
console.log("VERSION", VERSION); // 'v1',字符串
1
2
3
4

我们也可以通过@vue/cli提供的inspect (opens new window)命令,查看默认的webpack的配置:

通过@vue/cli创建的项目,内置vue-cli-service并提供了inspect命令

{
  "scripts": {
    "inspect:prod": "vue-cli-service inspect --mode='production'> config.prod.js",
    "inspect:dev": "vue-cli-service inspect --mode='development'> config.dev.js",
  }
}

1
2
3
4
5
6
7

我们可以看到其中DefinePlugin的用法:

/* config.plugin('define') */
new DefinePlugin(
  {
    'process.env': {
      NODE_ENV: '"development"',
      BASE_URL: '"/"'
    }
  }
),
1
2
3
4
5
6
7
8
9

EnvironmentPlugin

The EnvironmentPlugin is shorthand for using the DefinePlugin (opens new window) on process.env (opens new window) keys.

即:EnvironmentPlugin等效于:DefinePlugin在使用时,key为process.env上的简写

module.exports = {
  plugins: [
    new webpack.EnvironmentPlugin({
      test: 'test',
      debug: true,
    })
  ]
}
// 等效于:
// process.env.test设置为字符串'test'
// process.env.debug设置为布尔值true
1
2
3
4
5
6
7
8
9
10
11

index.js输出:

console.log("process.env.debug", process.env.debug); // true, 布尔值
console.log("process.env.test", process.env.test); // "test",字符串
1
2

参考:

# eslint

代码格式校验

eslint-webpack-plugin可用于开发阶段的代码校验

该插件诞生的目的是解决eslint-loader (opens new window)存在的问题,可参考文档 (opens new window)

选项 eslint-webpack-plugin eslint-loader
配置简单 YES NO
生成唯一的输出报告 YES NO
直接使用 eslint 的缓存 YES NO
仅改变文件 YES NO
# webpack中校验
npm install eslint-webpack-plugin eslint --save-dev
# 命令行校验
npm install eslint @babel/core @babel/eslint-parser -D
// for vue
// npm i eslint-plugin-vue --save-dev

// for react
// npm i eslint-plugin-react --save-dev
1
2
3
4
5
6
7
8
9

初始化eslint配置,可通过eslint --init命令:

1、如何使用eslint

// ? How would you like to use ESLint?  
To check syntax only
❯ To check syntax and find problems
  To check syntax, find problems, and enforce code style
1
2
3
4

2、使用的js模块类型

// ? What type of modules does your project use? …
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these
1
2
3
4

3、使用哪个框架

? Which framework does your project use? …
❯ React
  Vue.js
  None of these
1
2
3
4

4、是否使用ts

? Does your project use TypeScript? › No / Yes
1

5、代码运行环境

? Where does your code run?   (Press <space> to select, <a> to toggle all, <i> to invert selection)
✔ Browser
✔ Node
1
2
3

6、生成配置文件格式

? What format do you want your config file to be in? …
❯ JavaScript
  YAML
  JSON
1
2
3
4

注意:

  • 需要指定parser@babel/eslint-parser

    'parser': '@babel/eslint-parser'
    
    1
  • React17及以上(如果需要启用jsx检查),需要配置react的版本信息

    "settings": {
      "react": {
        "version": "detect"
      }
    }
    
    1
    2
    3
    4
    5

最终根据生成的.eslintrc.js修改后的配置文件,支持vue、react。

module.exports = {
    'root': true,
    'env': {
        'browser': true,
        'es2021': true,
        'node': true
    },
    'extends': [
        'eslint:recommended',
        // react
        'plugin:react/recommended',

        // vue
        // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x.
        // "plugin:vue/essential",
      
        // 'plugin:vue/vue3-recommended', // for Vue.js 3
    ],
    'parser': 'vue-eslint-parser', // vue需要配置自己的parser
    // 'parser': '@babel/eslint-parser', //
    'parserOptions': {
        'parser': '@babel/eslint-parser',
        'ecmaVersion': 10,
      	// https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
        // 'ecmaVersion': 12, // Parsing error: Unexpected token import (eslint)
        'sourceType': 'module',
        'ecmaFeatures': {
            'jsx': true
        },
    },
    'plugins': [
        'react',
        'vue'
    ],
    // react17之后,需要指定version版本
    // https://github.com/yannickcr/eslint-plugin-react/issues/2157
    "settings": {
        "react": {
            "version": "detect"
        }
    },
    'rules': {
        // .vue rule
        'vue/singleline-html-element-content-newline': ['off'],
        'vue/max-attributes-per-line': ['error', {
            'singleline': {
                'max': 8,
                'allowFirstLine': true
            },
            'multiline': {
                'max': 1,
                'allowFirstLine': false
            }
        }],
        'vue/html-indent': ['error', 4],

        'quotes': ['error', 'single'],
        'indent': ['error', 4],
        'no-unused-vars': ['error'],
        'no-irregular-whitespace': ['error', {skipComments: true}], // 禁止不规则的空白
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

注意:

1、"eslint:recommended" 启用的是在 规则页面 (opens new window) 中被标记为✅ 的规则,"eslint:all"指的是所有的eslint规则。

2、我们可以根据自己项目需求,扩展自己的eslint规则,参考使用可共享的npm包 (opens new window)可共享配置 (opens new window)。也可以使用其他的扩展(以eslint-config-开头的npm包)。可参考eslint-config-ivweb (opens new window)eslint-config-alloy (opens new window)

# 参考

vscode中配置eslint自动修复:

"editor.codeActionsOnSave": {
        "source.fixAll.eslint": true, // 保存时自动修复
},
1
2
3

# husky + lint-staged

# lint-staged

lint-staged,一个仅仅过滤出 Git 代码暂存区文件(被 git add 的文件)的工具。即:只检测暂存区的代码是否符合规范。

安装:

npm i lint-staged --save-dev
1

lint-staged配置

创建.lintstagedrc.js文件,并写入如下内容:

module.exports = {
    // 执行'lint-staged'时的指令集合
    "*.{js,jsx,vue}": [ 
        "eslint src",
        "git add"
    ]
};

1
2
3
4
5
6
7
8

或者在package.json中配置lint-staged选项,配置的优先级参考这里 (opens new window)

{
  "lint-staged": {
    "*.{js,jsx,vue}": [
      "eslint --fix src",
      "git add"
    ]
  },
  // 执行'npm run preCommit'命令,就会执行'lint-staged'
  "scripts": {
    "preCommit": "lint-staged"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# husky

作用:方便处理Git的各种钩子

# Git Hooks钩子

常用的git钩子,参考Git Hooks钩子 (opens new window)

名称 说明 绕过方法
pre-commit git commit 调用,在 commit 之前执行。检查即将提交的快照,以非 0 退出时,中断此次提交。可以用于代码的格式检查、运行测试用例等 --no-verify参数
commit-msg git commitgit merge 调用,以非 0 状态码退出时,会中断此次操作。可以用于对提交信息的校验。可参考这片文章 (opens new window)中关于commitlint的使用 --no-verify参数
pre-merge-commit git merge 调用,在 merge 之前执行,以非 0 状态退出时,会中断此次合并 --no-verify参数
pre-push git push 调用,在 git push 前执行,防止进行推送,以非 0 状态码退出时,会中断此次推送

# husky安装

安装husky:

npm i husky --save-dev
1

启用hooks钩子:

npx husky install // Enable Git hooks
// npm uninstall husky
1
2

如果没有安装npx,则全局安装npx

npm install -g npx
1

添加一条script脚本命令:

// npm v7版本才支持'set-script'命令
// npm v6版本可以直接编辑package.json,直接添加一条'prepare'指令
npm set-script prepare "husky install"
1
2
3

其作用就是在package.json中添加了一条prepare指令,如下所示:

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", // 测试用:返回1,提交失败
    "test": "echo \"Success\" && exit 0", // 测试用:返回0,正常提交
    "prepare": "husky install"
  }
1
2
3
4
5

添加一个husky钩子:

npx husky add .husky/pre-commit "npm test"
1

执行完 该命令后,会在.husky目录下生成一个名为pre-commit的shell脚本文件,如下图所示:

image-20210824094447107

钩子作用:在commit之前,调用pre-commit钩子。而在该钩子内部,会执行npm test命令,如果执行失败,则自动中断commit指令。

添加一条commit信息,用于测试钩子是否生效:

git add .husky/pre-commit
git commit -m "Keep calm and commit" // npm test返回非0,执行失败 --> commit失败
1
2

image-20210824093901148

由于npm test命令返回了1,因此,commit会失败。

# @vue/cli中的配置

如下为@Vue/clilint and fix on commit的配置:

@vue/cli中package.json中的的gitHooks配置,需要安装yorkie (opens new window)

// 1 用于commit,触发pre-commit钩子
// 2 该钩子调用lint-staged
// 3 如果校验通过,则执行`lint-staged`选项中配置的命令
"gitHooks": {
  "pre-commit": "lint-staged"
},
"lint-staged": {
    "*.{js,jsx,vue}": [
      "vue-cli-service lint",
      "git add"
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12

整个流程为:

  1. commit触发hooks的pre-commit钩子。
  2. pre-commit执行lint-staged进行校验。

# 参考文章

# commitizen

git commit msg提交规范

✨ feat:新功能
🐞 fix:修补bug
📃 docs:修改文档
🌈 style: 格式化代码结构,没有逻辑上的代码修改
🦄 refactor:重构,即不是新增功能,也不是修改bug的代码变动,比如重命名变量
🎈 perf: 性能优化
🧪 test:增加测试代码,单元测试用例
🔧 build:依赖相关内容
🐎 ci:ci配置相关,例如k8s,docker配置的修改
🐳 chore:改变构建流程
↩ revert: 版本回滚
1
2
3
4
5
6
7
8
9
10
11

# 发布lib

# verdaccio

使用verdaccio作为自由的npm仓库,使用方式可参考官网。使用pm2管理服务。

# 添加用户
npm adduser --registry http://121.199.54.25:32000
# 发布
npm publish --registry http://121.199.54.25:32000
# 卸载
npm unpublish --force

1
2
3
4
5
6
7

通过verdaccio命令,可查看配置文件服务地址

配置文件路径:/root/.config/verdaccio/config.yaml

image-20210829231756065

# 参考

# sourcemap

方案1、默认生成sourcemap

webpack配置如下:

module.exports = {
  devtool: 'sourcemap'
}
1
2
3

该方式会产生一个对应的sourcemap文件,同时在js源文件末尾会追加对应的map源文件的映射地址。

//# sourceMappingURL=index.3fe79d61.bundle.js.map
1

方案2、通过SourceMapDevToolPlugin来产生sourcemap

webpack配置如下:

module.exports = {
    // 注意SourceMapDevToolPlugin和devtool不可共存
    devtool: false, // false, source-map
    plugins: [
        new webpack.SourceMapDevToolPlugin({        
            filename: '[file].map',
            append: '\n//# sourceMappingURL=https://example.com/sourceMap/[url]'
    ]
};
1
2
3
4
5
6
7
8
9

该方式类似方案1,会产生一个对应的sourcemap文件,同时在js源文件末尾会追加对应的map源文件的映射地址。

注意:此方式会修改追加的映射地址

//# sourceMappingURL=https://example.com/sourceMap/index.3fe79d61.bundle.js.map
1

主要目的:

1、线上代码不放sourcemap,防止代码泄漏。

2、线上代码 出现问题,可方便本地调试。具体方式为:我们可以在本地host中添加一个域名https://example.com/sourceMap,并将它指向我们本地sourcemap服务器。

// host
https://example.com 192.168.4.200
1
2

# 参考

# FAQ

  • 如何在html文件中读取htmlWebpackPlugin配置项的值?可参考vue-cliBASE_URL取值?

    1、BASE_URL是通过DefinePlugin全局注入的变量;

    2、环境变量,是通过npm包dotenv来读取本地的.env文件。VUE CLI3的环境变量 (opens new window)也是使用的这个插件。

    3、在html中添加如下代码<div><%= JSON.stringify(htmlWebpackPlugin) %></div>,即可输出htmlWebpackPlugin的所有配置项。或者查看html-webpack-plugin (opens new window)文档。

    new webpack.DefinePlugin({
      "BASE_URL": JSON.stringify('https://api.example.com'),
      // 'process.env': {
      //     NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      // }
    }),
    
    1
    2
    3
    4
    5
    6

    htmlWebpackPlugin配置项的值如下图所示:

    image-20210818094125346

  • 如何协调本地开发与线上调试中关于sourcemap的问题?

    配合SourceMapDevToolPlugin,或者本地代理.map文件的访问。

  • external (opens new window)引入问题

    key为对应的模块名,value可以是字符串,或者对象:

    • value为字符串:其值为对应的库,挂载到"window"上的属性值
    • value为对象:参考external value is an object (opens new window)。需要注意的是,如果value为object时,则打包的lib库的libraryTarget必须为umd,其他情况下不支持。
    const externalCfg= {
        // 当value为对象的方式有问题,对于react、react-dom的module.exports都是undefined,
        // 参考:https://webpack.js.org/configuration/externals/#object
        // 原因:当value为对象时,只支持libraryTarget为'umd'. 当libraryTarget为其他值时不生效。
        // 'react': {
        //     root: 'React', commonjs2: 'react', commonjs: 'react', amd: 'react',
        // },
        // 'react-dom': {
        //     root: 'ReactDOM', commonjs2: 'react-dom', commonjs: 'react-dom', amd: 'react-dom',
        // },
        // 字符串方式:cdn外链引入正常,
        'react': 'React', // module.exports = React
        'react-dom': 'ReactDOM', // module.exports = ReactDOM
        // 字符串方式:cdn外链引入正常
      	// 注:值:"React"、"ReactDOM"指的是对应的库,挂载到"window"上的属性值。
        "react": "React", // module.exports = React
        "react-dom": "ReactDOM", // module.exports = ReactDOM
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
  • 当项目中通过vue-eslint-parser.vue进行eslint校验时,如下2种情况,对于() *=>* import('../xx.vue')语法会报错。

    module.exports = {
         'parser': 'vue-eslint-parser', // vue eslint parser(vue配置)
        'parserOptions': {
            'parser': '@babel/eslint-parser', // 自定义parser
            // "ecmaVersion": 6, // For ES6 syntax
            'ecmaVersion': 10,
            'sourceType': 'module',
            'ecmaFeatures': {
                'jsx': true
            },
        },
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12