npm script 的实践

2,697 阅读3分钟

打包环节

要实现

假设我们的项目结构是这样的

src
├── images
│   ├── a.png
│   └── b.png
├── index.html
├── scripts
│   └── index.js
└── styles
    ├── css.css
    └── less.css

构建过程要完成

  • 压缩图片;
  • 编译 less, 压缩 css;
  • 编译 es,压缩 js;
  • 给图片加版本号,并替换在 html、css、js 中的引用;
  • 给 css、js 加版本号,并替换在 html 中的引用;

安装依赖

npm i imagemin-cli less cssmin uglify-es uglify-js hashmark replaceinfiles -D
  • imagemin-cliimagemin 的命令行工具,用于图片构建(压缩);
  • cssmin 实现代码压缩。如果用的是预编译语言 less 自带命令行工具 lessc,或使用的是 sass 的可使用 node-sass
  • uglify-js 压缩代码,如果用的 ES6,那需要用 uglify-es 来进行压缩;
  • hashmark 自动添加版本号;
  • replaceinfiles 自动完成引用替换,将版本号的输出注入到文件和文件名中;

编写

1.创建目录与文件(并赋权,不做这步操作会这样,你可以试一下) 为什么要做这一步,是因为命令会比较长,前面章节[npm script 复杂场景的应用][]说过可以把复杂命令抽取到 .sh 文件中(应用 scripty)。

mkdir scripts/build
touch scripts/build.sh
touch scripts/build/{images,styles,scripts,hash}.sh
chmod -R a+x scripts

最终 scripts 目录树如下

scripts
├── build
│   ├── hash.sh
│   ├── images.sh
│   ├── scripts.sh
│   └── styles.sh
└── build.sh

2.图片处理文件(scripts/build/images.sh)脚本

#!/usr/bin/env bash

imagemin src/images/* --out-dir dist/images

3.样式处理文件(scripts/build/styles.sh)脚本

#!/usr/bin/env bash

for file in src/styles/*.css

do 
    lessc $file | cssmin > dist/styles/$(basename $file)
done

4.js 处理文件(scripts/build/scripts.sh)脚本

#!/usr/bin/env bash

for file in src/scripts/*.js

do 
    ./node_modules/uglify-es/bin/gulify $file --mangle > dist/scripts/$(basename $file)
done

4.资源版本号和引用替换(scripts/build/hash.sh)脚本

#!/usr/bin/env bash
# 给图片资源加上版本号,并且替换引用
hashmark -c dist -r -l 8 '**/*.{png,jpg}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'src/**/*.{css,html}' -d '{dir}/{base}'

# 给 js、css 资源加上版本号,并且替换引用
hashmark -c dist -r -l 8 '**/*.{css,js}' '{dir}/{name}.{hash}{ext}' | replaceinfiles -S -s 'src/**/*.html' -d 'dist/{base}'

5.文件 package.json 文件

{
    ...,
    "scripts": {
        "src:server": "http-server src/",
        "dist:server": "http-server dist -p $npm_package_config_urlPort",
        "dist:open": "open http://localhost:$npm_package_config_urlPort",

        "prebuild": "rm -rf dist && mkdir -p dist/{images,styles,scripts}",
        "build": "scripty",
        "build:images": "scripty",
        "build:styles": "scripty",
        "build:scripts": "scripty",
        "build:hash": "scripty",
        "postbuild": "npm-run-all --parallel dist:server dist:open"
    },
    "config": {
        "urlPort": 6011
    },
    ...
}

剖析

  • prebuild 每次构建前,清空之前的构建目录(这里应用了 npm 的钩子机制);
  • build:* 使用 scripty 将脚本抽取到单独文件(目录 scripts 和 srcipts/build 下)中,文件内容是对图片、less、css、js和html的处理工作,注意给 .sh 添加权限 chmod -R a+x scripts
  • 抽取的文件中应用到了 |(管道操作符) 和 >(输出重定向),这些都是 shell 语法;
  • hash.sh 是给资源加版本号,我们知道线上静态资源通常是放到 CDN(内容分发网络) 上的,或者是设置了长时间缓存,后期有版本迭代,这个时候资源更新了但是版本号没有更新,浏览器读取不到最新内容,这显然不是我们想要的。如果手动去加版本号,一是繁琐,二是 low(都不好意思自己是做前端的),三是不符合 DRY 原则,四是容易出错。所以,这个过程要做到自动化,通常就是将更新的文件名上做哈希,然后以这个哈希做为版本号,即版本号添加到文件名上,以实现引用的资源都是带版本号的,进而浏览器能读取到最新内容;
  • postbuild 启动静态资源服务和打开浏览器;

执行

npm run build

1.构建过程

2.文件 dist/index.html

3.文件 dist/css/css.css

本章内容代码 npm-script,自己体验一下吧,玩的愉快

你可以...

上一篇:npm script 应用在 git hooks 中

目录:npm script 小书