用webpack写个现代的JavaScript包

栏目: 编程语言 · 发布时间: 6年前

内容简介:webpack 作为目前主流的构建工具,其较快的版本迭代和复杂的配置方式,使得每次开发前不得不规划相当部分时间来调试。这里将记录整个环境的搭建过程,为新手提供基础思路。就像我在开发以上三个作为开发一个组件(

webpack 作为目前主流的构建工具,其较快的版本迭代和复杂的配置方式,使得每次开发前不得不规划相当部分时间来调试。这里将记录整个环境的搭建过程,为新手提供基础思路。

就像我在开发 vue-sitemap 时一样,构建 工具 往往需要达到下面几个需求:

  • 构建生成 CommonJS/UMD/ES Modules 三种模式的代码提供给使用者
  • 需运行测试和检查测试覆盖的进度
  • 开发时候使用VS Code 编辑器进行断点调试

以上三个作为开发一个组件( package )是基础中基础的需求,当然还有更多细节内容需要添加,由于篇幅过长另加文章再说吧。(欢迎各位读者评论留下你认为需要的功能( • ̀ω•́ )✧)

第一步:构建工具

接下来我们先从最基础的开始,需要安装Node.js(10.x) 作为所有代码的运行环境, 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 环境于是在这加上。

yarn 是一款快速、可靠、安全的依赖管理工具。如果你觉得 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:mainmodule 定义了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.jssrc/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 |                   |
----------|----------|----------|----------|----------|-------------------|
复制代码

简单说一下这四栏东西代表什么意思:

Statement coverage
Branch coverage
Function coverage
Line coverage

不在覆盖范围内的代码的行数会在 Uncovered Line 这栏显示。

为测试提供async/await支持

在测试中想使用async/await语法,需新增setup.js文件并在入口处添加 babel-polyfill

require("babel-polyfill");
复制代码

并在 .babelrc 修改 useBuiltInsentry

{
    ...
    "env": {
        "test": {
            "presets": [
                [
                    "env",
                    {
                        "useBuiltIns": "entry",
                        "modules": false,
                        "targets": {
                            "node": "current"
                        }
                    }
                ]
            ],
            "plugins": [
                "istanbul"
            ]
        }
    }
}
复制代码

接下来在 src/index.jstests/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 目录下的测试代码都能获得断点效果,想马上尝试可以下载本文例子 vscode-mocha-webpack-example ,安装依赖后就能尝试断点调试了。

设置参考源自 vscode-ts-webpack-node-debug-example

值得一提的是,上面参考例子原文说 devtool 使用 eval 相关的设置并不能断点,但是在使用 mocha-webpack 调试时上面例子并不能实现断点。在我和公司小伙伴多番寻找 vscodemocha-webpack 的issue后,经过各种尝试下发现设置成 eval-source-map 便能实现最佳断点效果(eval也能实现但是由于断点sourcemap指向的源是生成后的文件导致在断点时多少会产生偏移)。

吐槽:在使用 nvm 切换 nodejs 环境时发现 npm 下载不了,打开github的下载链接直接404了,惊悚地发现 npm 整个搬走 (`Д´*)9 ┴┴,为解决这个问题请下载最新版本 v1.1.7nvm

最后:

我的动力来自你的指头,请用你的指头使劲给我个赞吧!d(´ω` )

觉得本文有帮助的话不要忘记点一下收藏φ(>ω<*) 哦!

同时欢迎各路新手、大神在本文下方吐槽留言,谢谢参与讨论的各位仁兄!( • ̀ω•́ )✧

下面是本文完整例子,记得star一下!

同时非常感谢 Mather 协同编辑!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Fluent Python

Fluent Python

Luciano Ramalho / O'Reilly Media / 2015-8-20 / USD 39.99

Learn how to write idiomatic, effective Python code by leveraging its best features. Python's simplicity quickly lets you become productive with it, but this often means you aren’t using everything th......一起来看看 《Fluent Python》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具