1. 前端项目交付流程中需要考量的点能让我们更有大局观
  2. npm script视频链接: https://pan.baidu.com/s/1gfeZ619 密码: xx8j

前端工作流

  1. 代码风格检查
  2. 单元测试
    1. 测试运行
    2. 覆盖率收集
    3. 覆盖率查

软件工程师做的事情基本都是在实现自动化,比如:

  1. 各种业务系统是为了业务运转的自动化
  2. 部署系统是为了运维的自动化
  3. 对于开发者本身,自动化也是提升效率的关键环节,实际开发过程中也有不少事情是可以自动化的
  4. npm script 依赖 package.json
    1. Google Trends https://trends.google.com/trends/explore
  5. npm init 初始化 package.json
    1. 包名称、版本号、作者信息、入口文件、仓库地址、许可协议等,多数问题已经提供了默认值
  6. npm init -y 跳过参数,直接创建 package.json
  1. mkdir npm-demo & cd npm-demo
  2. npm init
  3. npm init -f # --force的意思
  4. npm init -y # --yes

将默认配置和 -f 参数结合使用,能让你用最短的时间创建 package.json

npm init

  1. package name: (npm-script)
  2. version: (0.1.0)
  3. description: hello npm script
  4. entry point: (index.js)
  5. test command:
  6. git repository:
  7. keywords: npm, script
  8. license: (MIT)

package.json

  1. {
  2. "name": "npm-script",
  3. "version": "0.1.0",
  4. "description": "npm script",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1"
  8. },
  9. "keywords": [
  10. "npm",
  11. "script"
  12. ],
  13. "author": "",
  14. "license": "MIT"
  15. }

npm config set init 修改 package.json的配置

  1. npm config set init.author.email "lulongwen@live.com"
  2. npm config set init.author.name "lulongwen"
  3. npm config set init.author.url "http://github.com/lulongwen"
  4. npm config set init.license "MIT"
  5. npm config set init.version "0.1.0"

npm run test

运行项目测试

  1. npm run test // 简写为 npm test,或 npm t
  2. npm test
  3. npm t

npm cache 清除缓存

  1. npm cache clean
  2. npm cache clean --force // 强制清除

npm内置命令

  1. npm start
  2. npm test

npm 是如何管理和执行各种 scripts?

  1. npm run 是 npm run-script的简写
  2. 当我们运行 npm run xxx 时,步骤如下
    1. 从 package.json 文件中读取 scripts 对象里面的全部配置
    2. 以传给 npm run 的第一个参数作为键,本例中为 xxx,在 scripts 对象里面获取对应的值作为接下来要执行的命令,如果没找到直接报错
    3. 在系统默认的 shell 中执行上述命令,系统默认 shell 通常是 bash
  3. npm run 原理:npm 在执行指定 script 之前会把 node_modules/.bin 加到环境变量 $PATH 的前面
    1. 任何内含可执行文件的 npm 依赖都可以在 npm script 中直接调用
    2. 你不需要在 npm script 中加上可执行文件的完整路径,比如 ./node_modules/.bin/eslint **.js

自定义 npm script

package.json如下:

  1. {
  2. "name": "npm-script",
  3. "devDependencies": {
  4. "eslint": "latest"
  5. },
  6. "scripts": {
  7. "eslint": "eslint **.js"
  8. }
  9. }

不带任何参数执行 npm run,会列出可执行的所有命令,比如下面这样

  1. Available scripts in the myproject package:
  2. eslint
  3. eslint **.js

运行 npm run eslint,npm 会在 shell 中运行 eslint **.js

eslint

  1. vue的 eslint:eslint-plugin-vue https://github.com/vuejs/eslint-plugin-vue
  2. react eslint
    1. eslint-plugin-react https://github.com/yannickcr/eslint-plugin-react
    2. eslint-plugin-react-native https://github.com/Intellicode/eslint-plugin-react-native
    3. eslint-config-airbnb 内置了 eslint-plugin-react https://www.npmjs.com/package/eslint-config-airbnb
  3. 存放规则集的文件就是配置文件,./node_modules/.bin/eslint --init
    1. 把 eslint 安装为项目依赖而非全局命令,项目可移植性更高
    2. eslint 内置了代码风格自动修复模式 --fix
  4. .eslintrc*
  1. module.exports = {
  2. env: {
  3. es6: true,
  4. node: true,
  5. },
  6. extends: 'eslint:recommended',
  7. rules: {
  8. indent: ['error', 2],
  9. 'linebreak-style': ['error', 'unix'],
  10. quotes: ['error', 'single'],
  11. semi: ['error', 'always'],
  12. },
  13. }

peerDependencies 安装失败问题可参照 npmjs 主页上的如下方法解决

  1. (
  2. export PKG=eslint-config-airbnb;
  3. npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest"
  4. )

给 npm script 传递参数以减少重复的 npm script

—fix,—是分隔符;要给 npm run lint:js 实际指向的命令传递额外的参数

  1. {
  2. "lint:js": "eslint *.js",
  3. "lint:js:fix": "eslint *.js --fix",
  4. }

npm run lint:js -- --fix

不想单独声明 lint:js:fix 命令,在需要的时候直接运行: npm run lint:js -- --fix 来实现同样的效果

eslint代码检查

  1. eslint 定制的 js 代码检查 https://eslint.org/
  2. stylelint 样式文件检查,支持 css、less、scss https://stylelint.io/
  3. jsonlint json文件语法检查 https://github.com/zaach/jsonlint
  4. markdownlint-cli https://github.com/igorshubovych/markdownlint-cli
  1. {
  2. "name": "npm-script",
  3. "version": "0.1.0",
  4. "main": "index.js",
  5. "scripts": {
  6. "lint:js": "eslint *.js",
  7. "lint:css": "stylelint *.less",
  8. "lint:json": "jsonlint --quiet *.json",
  9. "lint:markdown": "markdownlint --config .markdownlint.json *.md",
  10. "test": "mocha tests/"
  11. },
  12. "devDependencies": {
  13. "chai": "^4.1.2",
  14. "eslint": "^4.11.0",
  15. "jsonlint": "^1.6.2",
  16. "markdownlint-cli": "^0.5.0",
  17. "mocha": "^4.0.1",
  18. "stylelint": "^8.2.0",
  19. "stylelint-config-standard": "^17.0.0"
  20. }
  21. }

运行多个 npm命令

  1. npm-run-all
  2. && 符号把多条 npm script 按先后顺序串起来,&& 串行
    1. 把子命令的运行从串行改成并行,把连接多条命令的 && 符号替换成 & 即可,& 并行
  3. 串行执行的时候如果前序命令失败(通常进程退出码非0),后续全部命令都会终止执行
    1. & wait: 加上 wait 的额外好处是:子命令中启动了长时间运行的进程,可以ctrl + c 结束进程
    2. npm run all 代替 & await
  1. "scripts": {
  2. // 串行
  3. "test": "npm run lint:js && npm run lint:css && npm run lint:json && npm run lint:markdown && mocha tests/",
  4. // 并行
  5. "test": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/"
  6. }
  7. // 执行顺序
  8. eslint ==> stylelint ==> jsonlint ==> markdownlint ==> mocha

npm run all

https://github.com/mysticatea/npm-run-all/blob/HEAD/docs/npm-run-all.md

  1. npm i npm-run-all -D

package.json

  1. {
  2. "test": "npm-run-all lint:js lint:css lint:json lint:markdown mocha",
  3. // npm-run-all 还支持通配符匹配分组的 npm script,以上可以修改为 *
  4. "test": "npm-run-all lint:* mocha",
  5. // 让多个 npm script 并行执行
  6. "test": "npm-run-all --parallel lint:* mocha"
  7. }

让多个 npm script 并行执行, —parallel

并行执行的时候,并不需要在后面增加 & wait,因为 npm-run-all 已经帮我们做

  1. {
  2. "test": "npm-run-all lint:* mocha",
  3. "test": "npm-run-all --parallel lint:* mocha"
  4. }

在根目录的,最顶部引入 ployfill

  1. import '@babel/ployfill'

npm命令

  1. # 查看npm全局安装过的包
  2. npm list -g --depth 0
  3. npm fund # 捐赠

npm script 传递参数, —

  1. npm run lint:js -- --fix

不想单独声明 lint:js:fix 命令,在需要的时候直接运行: npm run lint:js -- --fix 来实现同样的效果

npm script 添加注释

  1. json 天然是不支持添加注释的,trick写法
  2. 增加 // 为键的值,注释就可以写在对应的值里面,npm 会忽略这种键,缺点:
    1. npm run 列出来的命令列表不能把注释和实际命令对应上,在命令前面加上注释
  1. {
  2. "//": "运行所有代码检查和单元测试",
  3. "test": "npm-run-all --parallel lint:* mocha"
  4. }
  1. CLI的本质是 shell 命令
    1. 注意:注释后面的换行符 \n 和多余的空格,
      1. 换行符是用于将注释和命令分隔开,这样命令就相当于微型的 shell 脚本
      2. 多余的空格是为了控制缩进,也可以用制表符 \t 替代
    2. 能让 npm run 列出来的命令更美观,但是 scripts 声明阅读起来不那么整齐
  1. {
  2. "test": "# 运行所有代码检查和单元测试 \n npm-run-all --parallel lint:* mocha"
  3. }
  1. 更好的做法: 把复杂的命令抽离到单独的文件中管理

npm script日志输出

运行 npm script 出现问题时,要要有能力去调试

  1. 默认的日志输出:不加任何日志控制参数得到的输出
  2. 显示尽可能少的有用信息
    1. 结合其他工具调用 npm script 的时候比较有用,—loglevel silent,或 —silent 控制
  3. 显示尽可能多的运行时状态
    1. 排查脚本问题的时候比较有用,需要使用 --loglevel verbose,或者 --verbose

npm script钩子

npm命令的执行增加了类似生命周期的机制

  1. pre
  2. post
  3. 在某些操作前需要做检查、某些操作后需要做清理的情况下非常有用
  4. 举例来说,运行 npm run test 的时候,分 3 个阶段:
    1. 检查 scripts 对象中是否存在 pretest 命令,如果有,先执行该命令;
    2. 检查是否有 test 命令,有的话运行 test 命令,没有的话报错;
    3. 检查是否存在 posttest 命令,如果有,执行 posttest 命令

覆盖率收集

改造 test

  1. 基于钩子机制对现有的 scripts 做以下 3 点重构,把代码检查和测试运行串起来
    1. 增加简单的 lint 命令,并行运行所有的 lint 子命令;
    2. 增加 pretest 钩子,在其中运行 lint 命令;
    3. 把 test 替换为更简单的 mocha tests/
  1. "lint": "npm-run-all --parallel lint:*",
  2. "lint:js": "eslint *.js",
  3. "lint:js:fix": "npm run lint:js -- --fix",
  4. "lint:css": "stylelint *.less",
  5. "lint:json": "jsonlint --quiet *.json",
  6. "lint:markdown": "markdownlint --config .markdownlint.json *.md",
  7. - "mocha": "mocha tests/",
  8. - "test": "# 运行所有代码检查和单元测试 \n npm-run-all --parallel lint:* mocha"
  9. + "pretest": "npm run lint",
  10. + "test": "mocha tests/",

运行 npm test 的时候,会先自动执行 pretest 里面的 lint

增加覆盖率收集

  1. 把运行测试和覆盖率收集串起来
    1. 做法:增加覆盖率收集的命令,并且覆盖率收集完毕之后自动打开 html 版本的覆盖率报告
  2. 覆盖率收集工具 nyc,是覆盖率收集工具 istanbul 的命令行版本,istanbul 支持生成各种格式的覆盖率报告
    1. 衡量测试效果的重要指标是:测试覆盖率
  3. 打开 html 文件的工具 opn-cli,是能够打开任意程序的工具 opn 的命令行版本
  1. npm i nyc opn-cli -D
  1. 然后在 package.json 增加 nyc 的配置,告诉 nyc 该忽略哪些文件。最后是在 scripts 中新增 3 条命令:
    1. precover,收集覆盖率之前把之前的覆盖率报告目录清理掉;
    2. cover,直接调用 nyc,让其生成 html 格式的覆盖率报告;
    3. postcover,清理掉临时文件,并且在浏览器中预览覆盖率报告
  2. 运行 npm run cover
  1. {
  2. " scripts":{
  3. "precover":"rm -rf coverage",
  4. "cover":"nyc --reporter=html npm test",
  5. "postcover":"rm -rf .nyc_output && opn coverage/index.html"
  6. },
  7. "devDependencies":{
  8. "npm-run-all":"^4.1.2",
  9. "nyc":"^11.3.0",
  10. "opn-cli":"^3.1.0",
  11. "stylelint":"^8.2.0",
  12. "stylelint-config-standard":"^17.0.0"
  13. },
  14. "nyc":{
  15. "exclude":[
  16. "**/*.spec.js",
  17. ".*.js"
  18. ]
  19. }
  20. }

环境变量

$PATH

正在执行的命令、包的名称和版本号、日志输出的级别

预定义变量

自定义变量

变量的使用方法遵循 shell 里面的语法,直接在 npm script 给想要引用的变量前面加上 $ 符号即可

  1. {
  2. "dummy": "echo $npm_package_name"
  3. }

postcover 做了 3 件事情:

  1. npm run cover:archive,归档本次覆盖率报告;
  2. npm run cover:cleanup,清理本次覆盖率报告;
  3. opn coverage_archive/$npm_package_version/index.html,直接预览覆盖率报告

npm 跨平台的兼容性

  1. linux, max兼容,window不兼容;不是所有的 shell 命令都是跨平台兼容的
  2. window建议使用 git bash 来运行 npm script,自带的 cmd 可能会遇到比较多的问题**
  3. npm script 的跨平台兼容注意点
    1. 所有使用引号的地方,建议使用双引号,并且加上转义
    2. 没做特殊处理的命令比如 eslint、stylelint、mocha、opn 等工具本身都是跨平台兼容的
    3. 使用 Linux 做开发
  4. NODE_ENV=test,NODE_ENV是 node的环境变量

cross-env 设置环境变量

cross-env 来实现 npm script 的跨平台兼容

  1. npm install cross-env --save-dev

package.json

  1. "scripts": {
  2. - "test": "NODE_ENV=test mocha tests/",
  3. + "test": "cross-env NODE_ENV=test mocha tests/",
  4. },

文件系统操作的跨平台兼容

  1. 跨平台兼容的包,npmjs.com上搜索 cross platform
  2. npm script涉及 目录的创建、删除、移动、复制等操作
    1. rimrafdel-cli,用来删除文件和目录,实现类似于 rm -rf 的功能;
    2. cpr,用于拷贝、复制文件和目录,实现类似于 cp -r 的功能;
    3. make-dir-cli,用于创建目录,实现类似于 mkdir -p 的功能
  1. pm install rimraf cpr make-dir-cli --save-dev

修改 package.json兼容

  1. "scripts": {
  2. - "cover:cleanup": "rm -rf coverage && rm -rf .nyc_output",
  3. - "cover:archive": "cross-var \"mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version\"",
  4. + "cover:cleanup": "rimraf coverage && rimraf .nyc_output",
  5. + "cover:archive": "cross-var \"make-dir coverage_archive/$npm_package_version && cpr coverage/* coverage_archive/$npm_package_version -o\"",
  6. "cover:serve": "cross-var http-server coverage_archive/$npm_package_version -p $npm_package_config_port",
  7. "cover:open": "cross-var opn http://localhost:$npm_package_config_port",
  8. - "postcover": "npm-run-all cover:archive cover:cleanup --parallel cover:serve cover:open"
  9. + "precover": "npm run cover:cleanup",
  10. + "postcover": "npm-run-all cover:archive --parallel cover:serve cover:open"
  11. },
  • rm -rf 直接替换成 rimraf
  • mkdir -p 直接替换成 make-dir
  • cp -r 的替换需特别说明下,cpr 默认是不覆盖的,需要显示传入 -o 配置项,并且参数必须严格是 cpr <source> <destination> [options] 的格式,即配置项放在最后面;
  • cover:cleanuppostcover 挪到 precover 里面去执行,规避 cpr 没归档完毕覆盖率报告就被清空的问题
  • 任何改动之后记得重新运行 npm run cover,确保所有的 npm script 还是按预期工作的

cross-var 引用变量

  1. 使用内置和预定义变量减少代码重复代码
  2. cross-var 实现跨平台的变量引用
    1. Linux 用 $npm_package_name
    2. Windows 用 %npm_package_name%
  3. 安装 cross-var
  1. npm install cross-var --save-dev

修改 package.json

  1. "scripts": {
  2. "cover:cleanup": "rm -rf coverage && rm -rf .nyc_output",
  3. - "cover:archive": "mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version",
  4. - "cover:serve": "http-server coverage_archive/$npm_package_version -p $npm_package_config_port",
  5. - "cover:open": "opn http://localhost:$npm_package_config_port",
  6. + "cover:archive": "cross-var \"mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version\"",
  7. + "cover:serve": "cross-var http-server coverage_archive/$npm_package_version -p $npm_package_config_port",
  8. + "cover:open": "cross-var opn http://localhost:$npm_package_config_port",
  9. "postcover": "npm-run-all cover:archive cover:cleanup --parallel cover:serve cover:open"
  10. },

直接在原始命令前增加 cross-var 命令即可

cover:archive 内含了两条子命令,我们需要用引号把整个命令包起来(注意这里是用的双引号,且必须转义),然后在前面加上 cross-var

引入 cross-var 之后,竟然还安装了 babel,如果想保持依赖更轻量的话,用 cross-var-no-babel

npm script实战

监听文件变化并自动运行 npm script

  1. 代码检查自动化,要借助 onchange 工具包来实现,
  2. 因为: stylelinteslintjsonlint 不全支持 —watch 模式
  3. onchange 可以方便的让我们在文件被修改、添加、删除时运行需要的命令
  4. onchange在运行指定命令之前,会输出哪个文件发生了哪些变化

安装 onchange

  1. npm install onchange --save-dev
  2. yarn add onchange -D

package.json添加 watch:lint 和 watch 两个子命令

  1. + "watch": "npm-run-all --parallel watch:*",
  2. + "watch:lint": "onchange -i \"**/*.js\" \"**/*.less\" -- npm run lint",
  3. "watch:test": "npm t -- --watch",
  1. watch:lint 里面的文件匹配模式可以使用通配符,但是模式两边使用了转义的双引号,做跨平台兼容的;
  2. watch:lint 里面的 -i 参数是让 onchange 在启动时就运行一次
  3. -- 之后的命令,即代码没变化的时候,变化前后的对比大多数时候还是有价值的
  4. watch 命令实际上是使用了 npm-run-all 来运行所有的 watch 子命令
    1. watch使用了跨平台的文件系统监听包 chokidar
    2. 你能基于 chokidar 做点什么有意思的事情呢?

单元测试自动化

  1. 运行 npm run watch:test
  2. 进程并没有退出,接下来尝试去修改测试代码,测试是不是自动重跑了!
  1. "test": "cross-env NODE_ENV=test mocha tests/",
  2. + "watch:test": "npm t -- --watch",
  3. "cover": "node scripts/cover.js",

live-reload自动刷新

  1. 前端开发,实际上最浪费时间的操作是什么?就是刷新页面
  2. 要让变更生效,需要重新加载,刷新页面的操作就变成了重复低效的操作
  3. create-react-app刷新用的是
  4. LiveReload的缺点:刷新页面意味着客户端状态的全部丢失,HMR、HR 都是基于 liveReload的优化
  5. Hot Module Replacement HMR,vue-cli用的就是 HMR提高效率
  1. npm install livereload http-server --save-dev
  2. yarn add livereload http-server -D

添加 npm script,client 命令能同时启动 livereload 服务、静态文件服务

运行 npm run client

  1. - "cover:open": "scripty"
  2. + "cover:open": "scripty",
  3. + "client": "npm-run-all --parallel client:*",
  4. + "client:reload-server": "livereload client/",
  5. + "client:static-server": "http-server client/"

为什么启动2个服务?

  1. http-server 启动的是静态文件服务器,启动后可以通过 http 的方式访问文件系统上的文件
  2. livereload 启动了自动刷新服务,负责监听文件系统变化,并在文件系统变化时通知所有连接的客户端
    1. index.html 中嵌入的那段 js 实际上是和 livereload-server 连接的一个 livereload-client
  3. index.html
  1. <body>
  2. <h2>LiveReload Demo</h2>
  3. <script>
  4. document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
  5. ':3579/livereload.js?snipver=1"></' + 'script>')
  6. </script>
  7. </body>

嵌入的 script,通过 判断 location.hostname 去检查当前页面运行环境,如果是线上环境就不嵌入了

或者使用打包工具处理 html 文件,上线前直接去掉即可

node配置自动检测文件改变不重启

  1. npm install -g nodemon
  2. nodemon ./bin/www
  3. 或者在npm start命令里把node改为nodemon

git hooks中运行 npm script

  1. prepost 的钩子机制,叫做 Git Hooks
  2. 钩子机制能让我们在代码 commit、push 之前(后)做自己想做的事情
  3. 通过 npm script 为本地仓库配置了 pre-commit、pre-push 钩子检查
    1. 本地检查:为了尽早给提交代码的同学反馈,哪些地方不符合规范,哪些地方需要注意
      1. pre-commit、pre-push
    2. 远程检查 Remotes:为了确保远程仓库收到的代码是符合团队约定的规范的
      1. pre-receive
      2. --no-verify(简写为 -n) 参数可以跳过本地检查
  4. npm script 和 git-hooks 的方案
    1. husky 支持更多的 Git Hooks 种类,再结合 lint-staged 试用就更溜
    2. pre-commit

husky

  1. npm install husky lint-staged --save-dev
  2. yarn add husky lint-staged -D

package.json

  1. "scripts": {
  2. "precommit": "npm run lint",
  3. "prepush": "npm run test",
  4. "lint": "npm-run-all --parallel lint:*",
  5. "lint:js": "eslint *.js",
  6. "test": "jest",
  7. "format": "prettier --single-quote --no-semi --write **/*.js",
  8. "install": "node ./bin/install.js",
  9. "uninstall": "node ./bin/uninstall.js"
  10. },

install 就是你在项目中安装 husky 时执行的脚本(所有的魔法都藏在在这里了

检查仓库的 .git/hooks 目录

  1. ls .git/hooks
  2. cat .git/hooks/pre-commit

lint-staged 改进 pre-commit

  1. lint 每次提交代码会检查所有的代码,比较慢就不说了,初期 lint 工具可能会报告几百上千个错误,让人崩溃
  2. lint-staged 来缓解这个问题,每个团队成员提交的时候,只检查当次改动的文件
  1. "scripts": {
  2. - "precommit": "npm run lint",
  3. + "precommit": "lint-staged",
  4. "prepush": "npm run test",
  5. "lint": "npm-run-all --parallel lint:*",
  6. },
  7. + "lint-staged": {
  8. + "*.js": "eslint",
  9. + "*.less": "stylelint",
  10. + "*.css": "stylelint",
  11. + "*.json": "jsonlint --quiet",
  12. + "*.md": "markdownlint --config .markdownlint.json"
  13. + },

尝试提交这个文件:git commit -m 'add eslint error' index.js

如果 husky 的 pre-commit 钩子执行失败,提交也就没有成功

husky 和 lint-staged 构建超溜的代码检查工作流 https://juejin.im/post/6844903479283040269

npm script构建流水线

  1. 部署前最关键的环节就是构建,构建环节要完成的事情:
    1. 源代码预编译:比如 less、sass、typescript;
    2. 图片优化、雪碧图生成;
    3. JS、CSS 合并、压缩;
    4. 静态资源加版本号和引用替换;
    5. 静态资源传 CDN 等
  2. 大多数项目构建都是脚手架配置好的,但要知道构建过程的原理
  3. 构建过程必须遵循下面的步骤
    1. 压缩图片;
    2. 编译 less、压缩 css;
    3. 编译、压缩 js;
    4. 给图片加版本号并替换 js、css 中的引用;
    5. 给 js、css 加版本号并替换 html 中的引用

构建过程

  1. 构建产生的结果代码,放在 dist 目录
  2. 每次构建前,清空之前的构建目录
    1. 构建过程分为:images、styles、scripts、hash 四个步骤
  3. 利用 npm 的钩子机制添加 prebuild 命令
  1. {
  2. "client:static-server": "http-server client/",
  3. "prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}"
  4. }

图片构建的经典工具是 imagemin,提供了命令行版本 imagemin-cli

  1. npm install imagemin-cli --save-dev
  2. yarn add imagemin-cli -D

scripts/build/images.sh 中添加 imagemin client/images/* --out-dir=dist/images

package.json 中添加 build:images 命令

运行 npm run prebuild && npm run build:images,然后观察 dist 目录的变化

  1. "build:images": "scripty"

样式构建

less

node-sass

cssmin 来完成代码预压缩

  1. npm install cssmin --save-dev

运行 npm run prebuild && npm run build:styles

js构建

uglify-es 来进行 es6代码压缩, uglify-es配置 https://github.com/mishoo/UglifyJS/tree/harmony#command-line-options

uglify-js 来压缩 js代码

  1. npm install uglify-es --save-dev

静态资源版本号

  1. 静态资源加版本号的原因:是线上环境的静态资源通常都放在 CDN 上,或者设置了很长时间的缓存
  2. 如果资源更新了但没有更新版本号,浏览器端是拿不到最新内容的
  3. 手动加版本号的过程很繁琐并且容易出错
  4. 通常的做法是利用文件内容做哈希,比如 md5
  5. hashmark,自动添加版本号;
  6. replaceinfiles,自动完成引用替换,它需要将版本号过程的输出作为输入
  1. npm install hashmark replaceinfiles --save-dev