https://webpack.js.org/ 作为目前主流的构建工具, 其较快的版本迭代和复杂的配置方式, 使得每次开发前不得不规划相当部分时间来调试. 这里将记录整个环境的搭建过程, 为新手提供基础思路.
就像我在开发 vue-sitemap 时一样, 构建工具往往需要达到下面几个需求:
构建生成 CommonJS/UMD/ES Modules 三种模式的代码提供给使用者
需运行测试和检查测试覆盖的进度
开发时候使用 VS Code https://code.visualstudio.com/ 编辑器进行断点调试
以上三个作为开发一个组件 (package) 是基础中基础的需求, 当然还有更多细节内容需要添加, 由于篇幅过长另加文章再说吧.(欢迎各位读者评论留下你认为需要的功能( • ̀ω•́ ))
第一步: 构建工具
接下来我们先从最基础的开始, 需要安装 Node.JS(10.x) https://nodejs.org/zh-cn/ 作为所有代码的运行环境, webpack 也是一样.
初始化项目
由于我需要把项目发布至 NPM 的, 使用命令初始化项目描述文件 package.JSON
NPM init
初次化细节各位读者找其他文章补全吧, 这里不细说
接下来看看目录结构
│ package.JSON // 项目描述文件
│ README.md //GitHub 创建仓库时默认创建
├─src // 源代码目录
│ index.JS // 入口文件
├─tests // 测试代码目录
│
├─dist // 生产文件的目录
│
└─docs // 文档目录
添加 webpack
- NPM install -D webpack webpack-cli cross-env
- //or
- //yarn add webpack webpack-cli cross-env -D
这里使用的 webpack v4, 后续设置也是基于 4 来设置, cross-env 是帮助在 win 下能正常使用环境变量的包, 我开发在 win 环境于是在这加上.
https://www.yarnpkg.com/zh-Hans/ 是一款快速, 可靠, 安全的依赖管理工具. 如果你觉得 NPM 安装时候较慢的话, 不妨试试.
等依赖下载解决完毕之后,, 在 package.JSON 设置构建命令方便之后使用.
- //# package.JSON
- {
- //...
- "scripts": {
- "build": "cross-env NODE_ENV=production webpack --propress --hide-modules",
- }
- }
这里我们可以尝试运行一下命令 NPM run build 尝试能否构建成功, 成功的情况下在 dist 目录下会生成 main.JS 的文件.
配置 webpack
创建 webpack.config.JS 文件来配置 webpack . 为满足我们的第一个需要生成三种模式的代码:
- //# webpack.config.JS
- const package = require('./package.json')
- const path = require('path')
- const config = {
- entry: "./src/index.js", // 入口文件
- output: { // 输出设置
- path: path.resolve(__dirname, "./dist"),
- filename: `${package.name}.js`
- },
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "./src")
- }
- }
- }
- if (process.env.NODE_ENV === "umd") {
- config.optimization = { minimize: false };
- config.output.library = package.name;
- config.output.libraryTarget = "umd2";
- config.output.filename = `${package.name}.js`;
- }
- if (process.env.NODE_ENV === "umd:min") {
- config.output.library = package.name;
- config.output.libraryTarget = 'umd2';
- config.output.filename = `${package.name}.min.js`;
- }
- if (process.env.NODE_ENV === "es") {
- config.output.library = package.name;
- config.output.libraryTarget = "amd";
- config.output.filename = `${package.name}.es.js`;
- }
- if (process.env.NODE_ENV === "commonjs") {
- config.output.library = package.name;
- config.output.libraryTarget = "commonjs2";
- config.output.filename = `${package.name}.common.js`;
- }
- module.exports = config
添加构建命令
为 package.JSON 添加新的运行命令
- //# package.JSON
- {
- "version": "0.1.0",
- "name": "vscode-mocha-webpack-example",
- "description": "用于管理导航, 面包屑及路由等基于 vue 的功能整合",
- "main": "./src/index.js",
- "scripts": {
- "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min",
- "build:umd": "cross-env NODE_ENV=umd webpack --mode=production --progress --hide-modules",
- "build:umd:min": "cross-env NODE_ENV=umd:min webpack --mode=production --progress --hide-modules",
- "build:es": "cross-env NODE_ENV=es webpack --mode=production --progress --hide-modules",
- "build:commonjs": "cross-env NODE_ENV=commonjs webpack --mode=production --progress --hide-modules"
- }
- ...
- }
运行 NPM run build 就会 CommonJS/UMD/ES Modules 三种模式生成对应的文件.
大概是这样子:
├─dist
│ vscode-mocha-webpack-example.common.JS
│ vscode-mocha-webpack-example.es.JS
│ vscode-mocha-webpack-example.min.JS
│ vscode-mocha-webpack-example.JS
指定终端
为了使你的构建文件成为最终发布包的一部分, 你必须声明它们. 将以下内容添加到 package.JSON:
- "main": "dist/vscode-mocha-webpack-example.common.js",
- "module": "dist/vscode-mocha-webpack-example.es.js",
- "jsnext:main": "dist/vscode-mocha-webpack-example.es.js",
- "files": [
- "dist",
- "src"
- ],
files 部分告诉 NPM 在发布时打包这些文件夹(否则, 它们将被忽略, 因为它们列在. gitignore 文件中)
main 定义 CommonJS 构建的终端
jsnext:main 和 module 定义了 ES2015 构建的终端(我们定义了两个终端, 因为 jsnext:main 是最早使用的规范, 而 module 则更符合标准规范).
第二步, 设置 babel
通过 babel 使得我们使用最新的语法, 而不必担心运行环境不支持的问题. 在 webpack 的下我们需要用到 babel-loader 来导入 babel 支持, 关于最新的兼容设置还需使用上 babel-preset-env:
- NPM install -D babel babel-cli babel-preset-env
- //or
- //yarn add babel babel-cli babel-preset-env -D
创建 babel 配置文件
接着在. babelrc 文件里设置 babel 兼容的规则:
- {
- "presets": [
- [
- "env",
- {
- "useBuiltIns": false,
- "modules": false
- }
- ]
- ]
- }
为 webpack 添加 babel-loader
当我们使用最新语法编写 JavaScript 时, webpack 会匹配将所有 JS 文件给 babel 的处理.
- const package = require('./package.json')
- const path = require('path')
- const config = {
- entry: "./src/index.js",
- output: {
- path: path.resolve(__dirname, "./dist"),
- filename: `${package.name}.js`
- },
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "./src")
- }
- },
- module: {
- rules: [
- {
- test: /\.JS$/,
- loader: 'babel-loader',
- exclude: /node_modules/
- }
- ]
- }
- }
- ...
- module.exports = config
当运行构建时 webpack 便会加载 babel 及其相关的设置将代码转换并生成, 到这步构建相关的设置基本完成.
第三步, 添加自动化测试
相信对自动化测试有所了解的读者应该对 mocha 并不陌生, 不了解的可以先去补补相关知识再往下看. 简单的测试较多使用 mocha 来进行处理, 还有断言库 chai 和提供 promise 支持的 chai-as-promised 等等, 下面先把这些依赖安装上:
- NPM install -D mocha mocha-webpack chai chai-as-promised
- //or
- //yarn add mocha mocha-webpack chai chai-as-promised -D
测试代码想使用 es 新特性时可以使用 mocha-webpack 这个插件.
然后在 package.JSON 添加上测试命令:
- {
- //...
- "scripts": {
- "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min",
- "build:umd": "cross-env NODE_ENV=umd webpack --mode=production --progress --hide-modules",
- "build:umd:min": "cross-env NODE_ENV=umd:min webpack --mode=production --progress --hide-modules",
- "build:es": "cross-env NODE_ENV=es webpack --mode=production --progress --hide-modules",
- "test": "cross-env NODE_ENV=test mocha-webpack tests/**/*.spec.js"
- }
- //...
- }
.babelrc 也需要设置一下:
- {
- //...
- "env": {
- "test": {
- "presets": [
- [
- "env",
- {
- "modules": false,
- "targets": {
- "node": "current"
- }
- }
- ]
- ]
- }
- }
- }
为了能测试添加 tests/unit/example.spec.JS 和 src/index.JS 两个文件, 代码如下:
├─src
│ index.JS
└─tests
└─unit
example.spec.JS
- //# src/index.JS
- export function getRole(user){
- switch(user){
- case "Packy":
- return "admin"
- case "Joan":
- return "reader"
- }
- }
- //# tests/unit/example.spec.JS
- import { assert } from "chai";
- import { getRole } from "@/index";
- describe('Testing', ()=>{
- it('Packy is admin', () => { assert.equal(getRole('Packy'), 'admin') })
- it("Joan is reader", () => { assert.equal(getRole("Joan"), "reader") });
- })
现在运行测试命令就能得出测试结果了:
NPM run test
大概输出是这个样子:
- WEBPACK Compiling...
- [======================= ] 91% (additional chunk assets processing)
- WEBPACK Compiled successfully in 5893ms
- MOCHA Testing...
- Testing
√ Packy is admin
√ Joan is reader
- 2 passing (39ms)
- MOCHA Tests completed successfully
关于测试覆盖率的问题
有了测试还得知道测试是否都覆盖了所有代码(听说基本要到 80%, 有些团队可能要求更高 90~95%), 那如何得知?
nyc 这个包就能帮助到我去检验测试覆盖率, 首先先安装依赖:
NPM install -D nyc babel-plugin-istanbul
再设置检查范围和添加命令:
- //# package.JSON
- {
- ...
- "scripts": {
- "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min",
- "build:umd": "cross-env NODE_ENV=umd webpack --mode=production --progress --hide-modules",
- "build:umd:min": "cross-env NODE_ENV=umd:min webpack --mode=production --progress --hide-modules",
- "build:es": "cross-env NODE_ENV=es webpack --mode=production --progress --hide-modules",
- "build:commonjs": "cross-env NODE_ENV=commonjs webpack --mode=production --progress --hide-modules",
- "test": "cross-env NODE_ENV=test nyc mocha-webpack tests/**/*.spec.js"
- },
- ...
- "nyc": {
- "include": [
- "src/**"
- ],
- "instrument": false,
- "sourceMap": false
- }
- ...
- }
安装依赖中也看到 babel 也需要添加相关的设置:
- //# .babelrc
- {
- ...
- "env": {
- "test": {
- "presets": [
- [
- "env",
- {
- "modules": false,
- "targets": {
- "node": "current"
- }
- }
- ]
- ],
- "plugins": [
- "istanbul"
- ]
- }
- }
- }
运行 NPM run test 将会得到以下内容:
- WEBPACK Compiling...
- [======================= ] 91% (additional chunk assets processing)
- WEBPACK Compiled successfully in 5893ms
- MOCHA Testing...
- Testing
√ Packy is admin
√ Joan is reader
- 2 passing (39ms)
- MOCHA Tests completed successfully
- ----------|----------|----------|----------|----------|-------------------|
- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
- ----------|----------|----------|----------|----------|-------------------|
- All files | 100 | 100 | 100 | 100 | |
- index.JS | 100 | 100 | 100 | 100 | |
- ----------|----------|----------|----------|----------|-------------------|
简单说一下这四栏东西代表什么意思:
Stmts : Statement coverage 声明覆盖率, 程序中的每个语句都已执行吗?
Branch: Branch coverage 分支覆盖率, 是否已执行每个控制结构的每个分支(也称为 DD 路径)(例如 if 和 case 语句)? 例如, 给定 if 语句, 是否已执行 true 和 false 分支?
Funcs: Function coverage 方法覆盖率, 是否已调用程序中的每个函数(或子例程)?
Lines: Line coverage 行代码覆盖, 是否已执行源文件中的每个可执行的行?
不在覆盖范围内的代码的行数会在 Uncovered Line 这栏显示.
为测试提供 async/await 支持
在测试中想使用 async/await 语法, 需新增 setup.JS 文件并在入口处添加 babel-polyfill:
require("babel-polyfill");
并在. babelrc 修改 useBuiltIns 为 entry:
- {
- ...
- "env": {
- "test": {
- "presets": [
- [
- "env",
- {
- "useBuiltIns": "entry",
- "modules": false,
- "targets": {
- "node": "current"
- }
- }
- ]
- ],
- "plugins": [
- "istanbul"
- ]
- }
- }
- }
接下来在 src/index.JS 和 tests/example.spec.JS 两个文件添加新的代码:
- //# src/index.JS
- export function getUsers(){
- return new Promise((resolve, reject)=>{
- setTimeout(()=>{
- console.log('123')
- resolve(['Packy', 'Joan'])
- }, 1000)
- })
- }
- //# tests/unit/example.spec.JS
- describe('GetUsers', ()=>{
- it('get result is Array', async ()=>{
- const users = await getUsers();
- assert.isArray(users, "[message]");
- })
- })
运行测试就能看到效果!
让测试更进一步, 在 VS Code 中调试
想在 VS Code 断点调试代码需要额外增加一些设置, 添加以下代码至 webpack.config.JS.
- //# webpack.config.JS
- //...
- if (process.env.NODE_ENV === "test") {
- config.devtool = "eval-source-map";
- config.output = Object.assign(config.output, {
- devtoolModuleFilenameTemplate: "[absolute-resource-path]",
- devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]'
- });
- }
- module.exports = config;
在 VS Code 添加调试代码
打开 VS Code 调试面板在下拉选项中选择添加配置(或者直接创建并打开. vscode/launch.JSON 文件):
- // 使用 IntelliSense 了解相关属性.
- // 悬停以查看现有属性的描述.
- // 欲了解更多信息, 请访问: https://go.microsoft.com/fwlink/?linkid=830387
- {
- "version": "0.2.0",
- "configurations": [
- {
- "type": "node",
- "request": "launch",
- "name": "Mocha-webpack Tests",
- "program": "${workspaceFolder}/node_modules/mocha-webpack/bin/mocha-webpack",
- "args": [
- "--full-trace",
- "--timeout",
- "999999",
- "--colors",
- "tests/**/*.js"
- ],
- "sourceMaps": true,
- "env": {
- "NODE_ENV": "test"
- },
- "internalConsoleOptions": "openOnSessionStart"
- }]
- }
在 src 目录下的源代码或是 tests 目录下的测试代码都能获得断点效果, 想马上尝试可以下载本文例子, 安装依赖后就能尝试断点调试了.
设置参考源自
值得一提的是, 上面参考例子原文说 devtool 使用 eval 相关的设置并不能断点, 但是在使用 mocha-webpack 调试时上面例子并不能实现断点. 在我和公司小伙伴多番寻找 vscode 和 mocha-webpack 的 issue 后, 经过各种尝试下发现设置成 eval-source-map 便能实现最佳断点效果(eval 也能实现但是由于断点 sourcemap 指向的源是生成后的文件导致在断点时多少会产生偏移).
吐槽: 在使用 nvm 切换 Node.JS 环境时发现 NPM 下载不了, 打开 GitHub 的下载链接直接 404 了, 惊悚地发现 NPM 整个搬走 (`Д´*)9 ┴┴, 为解决这个问题请下载最新版本 v1.1.7 的 nvm.
最后:
我的动力来自你的指头, 请用你的指头使劲给我个赞吧! d(´ω` )
觉得本文有帮助的话不要忘记点一下收藏φ(>ω<*) 哦!
同时欢迎各路新手, 大神在本文下方吐槽留言, 谢谢参与讨论的各位仁兄!( • ̀ω•́ )
下面是本文完整例子, 记得 star 一下!
同时非常感谢 Mather https://github.com/409915016 协同编辑!
来源: https://juejin.im/post/5bfca0e8f265da611204b3ca