# 可维护的webpack构建配置

# 构建配置抽离成npm包的意义

  • 通用性
    业务开发者无需关注构建配置
    统一团队构建脚本
  • 可维护性
    构建配置合理的拆分
    README文档说明,ChangeLog版本修订说明等
  • 质量 单元测试、测试覆盖率等
    持续集成

# 构建配置管理的可选方案

1、通过多个配置文件管理不同环境的构建,webpack --config 参数进行控制
2、将构建配置设计成一个库,比如:hjs-webpackwebpack-blocks
3、抽成一个工具进行管理,比如:create-react-appvue/cli
4、将所有的配置放到一个文件里,通过参数控制, --env 参数控制分支选择

# 构建配置包设计

通过一二方案进行构建包的设计方案可适合小团队选择,而这次通过多个配置文件管理不同环境的webpack配置。
webpack.base.js,基础配置,完成一些通过的构建配置项
webpack.dev.js,开发环境
webpack.prod.js,生产环境
webpack.ssr.js,SSR环境,如果需要考虑到服务器端渲染的

将配置文件抽离成一个npm包统一管理: * 规范:Git commit日志,README配置说明,ESLint规范等
* 质量:单元测试,覆盖率测试,持续集成CI等

通过webpack-merge合并配置项。

const merge = require('webpack-merge')

module.exports = merge(baseConfig,devConfig)

# 功能模块设计及目录结构设计

# 功能模块

功能模块

# 目录结构

.
├── test  // 测试用例
├── lib   // 构建配置源码
|   ├── webpack.base.js
|   └── webpack.dev.js
|   └── webpack.prod.js
|   └── webpack.ssr.js
├── package.json // 依赖包配置说明
├── README.md
├── CHANGELOG.md      
├── .eslinrc.js    
└── index.js     

# 使用ESLint规范构建脚本

新建.eslintrc.js文件,配置eslint规范来规范构建脚本。

安装依赖

npm i eslint eslint-config-airbnb-base babel-eslint eslint-plugin-import@latest  -D

配置.eslintrc.js

module.exports = {
    "parser": "babel-eslint",
    "extends": 'airbnb-base',
    "rules": {
        "indent": ["error",4]
    },
    "env": { // 当前生效环境
        "browser": true,
        "node": true
    }
}

添加scripts启动命令

//package.json
{
    "srcipts": {
        "eslint": "eslint ./lib --fix"
    }
}

# 功能测试

# 冒烟测试

冒烟测试是在软件开发过程中的一种针对软件版本包的快速基本功能验证策略,是对软件基本功能进行确认验证的 手段,并非对软件版本包的深入测试。冒烟测试也是针对软件版本包进行详细测试之前的预测试,执行冒烟测试的 主要目的是快速验证软件基本功能是否有缺陷。

# 执行冒烟测试

1、构建是否成功

安装rimraf依赖包,用来删除每次build生成的dist文件夹。

npm i rimraf -D

新建template测试用例,并运行webpack.prod.js,查看是否构建dist目录

const path = require('path')
const webpack = require('webpack')
const rimraf = require('rimraf')

//process.chdir() 方法变更 Node.js 进程的当前工作目录,默认template目录执行
process.chdir(path.join(__dirname, 'template'))

rimraf('./dist', () => {
    const prodConfig = require('../../lib/webpack.prod')
    // 运行webpack配置
    webpack(prodConfig, (err,stats) => {
        if(err){
            console.error(err)
            return
        }
        console.log(stats.toString({
            colors:true,
            modules:false,
            children:false,
            chunks:false,
            chunkModules:false
        }))

        console.log('Compiler success...')
    })
})

运行```node tests/smoke/index.js ``

2、每次构建完成build目录是否有内容输出

目前常用的单元测试库有Mocha+chai和Jest,其中Mocha是单纯的测试框架,需要配合 chai、should.js、expect、better-assert等断言库;而Jest是一个集成的测试框架, 可开箱即用。

其中,常用的api有:

  • describe:定义一个测试套件
  • it:定义一个测试用例
  • expect:断言的判断条件
  • toBe:断言的比较结果

安装jest,运行命令行jest后会自动运行项目下所有.test.js和.spec.js这种格式的文件。

npm i jest -D

smoke下新建html.test.js和css.test.js文件,测试是否有生成html、css、js文件。

//html.test.js
const glob = require('glob-all')

describe('检查构建文件是否存在',() => {
    it('检查html文件是否构建',(done) => {
        const files = glob.sync([
            './dist/index.html',
            './dist/about.html'
        ])
        if(files.length > 0){
            done()
        } else {
            throw new Error('没有找到html文件')
        }
    })
})
//css.test.js
const glob = require('glob-all')

describe('检查构建文件是否存在',() => {
    it('检查css && js文件是否构建',(done) => {
        const files = glob.sync([
            './dist/index_*.js',
            './dist/about_*.js',
            './dist/index_*.css'
        ])
        if(files.length > 0){
            done()
        } else {
            throw new Error('没有找到对于css && js文件')
        }
    })
})

运行命令 jest 后会自动运行项目下所有.test.js和.spec.js这种格式的文件。 配置scripts启动命令,设置运行tests目录下的smoke冒烟测试用例。

{
    "srcipts":{
        "jest:test": "jest tests/smoke"
    }
}

# 单元测试

tests/unit文件夹,新建webpack-base.test.js单元测试用例,对webpack.base.js进行单元测试。

//webpack-base.test.js
const path = require('path')

process.chdir(path.join(__dirname, '../smoke/template'))

describe('webpack.base.js 测试用例', () =>{

    const baseConfig = require('../../lib/webpack.base')

    // console.log(baseConfig)
    it('entry', () => { // 入口文件测试
        expect(baseConfig.entry.index)
            .toBe('D:/github/blogCode/webpack/webpack-builder/tests/smoke/template/src/index/index.js')
        expect(baseConfig.entry.about)
            .toBe('D:/github/blogCode/webpack/webpack-builder/tests/smoke/template/src/about/index.js')
    })
})

在package.json中新增scripts字段,设置单元测试命令行。··

{
    "scripts":{
        "test:unit": "jest tests/unit --config jest.config.json"
    }
}

其中,tests/unit为执行单元测试的目录脚本,--config jest.config.json为指定jest.config.json配置,设置 进行单元覆盖率测试的统计。

//jest.config.json
{
  "collectCoverage": true, //打开代码覆盖率的开关
  "collectCoverageFrom": ["lib/*.js"] // 配置哪些文件需要收集覆盖率
}

运行npm run test:unit可获得对于测试通过率及测试覆盖率:

# 持续集成

持续集成其核心就是在代码集成到主干之前,通过自动化测试。只要有一个测试用例失败就不能集成,能快速的发现问题并及时修复。
持续集成能快速发现错误,防止分支大幅偏离主干,保证代码的质量。

GitHub最流行的CI:

# 接入Travis CI

1、使用GitHub账号登录 https://travis-ci.org/
2、在https://travis-ci.org/account/repositories为项目开启权限
3、在项目根目录下新增.travis.yml CI配置文件,则每次git commit提交时会触发配置的脚本

yml文件内容主要包括:

language: node_js 
sudo: false

cache: #是否需要开启缓存,下次运行时CI可以更快速的安装node_modules
    apt:true
    directories:
      - node_modules 
     
node_js: stable #设置相应的版本

intall:
    - npm install -D #安装构建包依赖
    -cd ./tests/smoke/template
    - npm install -D #安装模板 项目依赖
    - cd ../../../ #返回到当前脚本运行目录
    
script:
    - npm run test:unit

Travis 的运行流程很简单,任何项目都会经过两个阶段:
install 阶段:安装依赖
script 阶段:运行脚本
如果运行成功的话,项目会添加build passing标示

travis-CI

# 发布构建包

命令行执行npm login登录npm社区,并执行npm publish即可完成当前包的发布。

如果需要进行依赖包版本升级则,对于的升级版本:
npm version patch:升级补丁版本号
npm version minor:升级小版本号
npm version major:升级大版本号

# Git规范及Changelog生成

良好的Git commit提交规范可以加快Code Review的流程;可以根据Git Commit提交数据生产Changelog 日志信息;并且后续维护者可以快速定位被修改的原因。

技术方案:
commit规范

commit提交格式规范:

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

type:表示某次提交的类型,其类型: feat:新增feature
fix:修复bug
docs:仅修改了文档,比如README,CHANGELOG,CONTRIBUTE等
style:仅修改了空格、格式缩进等,不改变代码逻辑
refactor:代码重构,没有加新功能或者修复bug
perf:优化相关,比如提升性能、体验
test:测试用例,比如单元测试,集成测试等
chore:改变构建流程或者增加依赖库,工具等
revert:回滚到上一个版本

安装依赖并设置本地开发阶段添加precommit钩子

npm i husky validate-commit-msg conventional-changelog-cli -D

precommit钩子。

//package.json
{
    "scripts":{
        "commitmsg": "validate-commit-msg",
        "changelog": "conventional-changelog -p angular -i CHANGELOG.d -s -r 0"
    }
}

# 开源版本号规范

软件的版本通常由三位组成,形如:X.Y.Z,其中主版本号一般标示为做了不兼容API的修改,次版本号为做了 向下兼容的功能性新增;而修订号则表示做了向下兼容的问题修正。
遵守semver规范可以有效的避免出现循环依赖及依赖冲突的减少。

# 推荐阅读

持续集成Travis CI:http://www.ruanyifeng.com/blog/2017/12/travis_ci_tutorial.html

semver规范:https://www.jianshu.com/p/a7490344044f