npm Scripts 入门学习(2)

近来直接使用node package提供的命令行界面的情绪持续高涨,反之,人们对通过运行任务从而屏蔽抽象功能的热情逐渐降温。在一定程度是,你无论如何都要使用npm,而同时npm提供了脚本功能,为什么不用呢?但是我们使用npm的脚本功能的原因有很多。Damon会帮我们理解这样做的原因,并确切的告诉我们如何通过这种方式来完成前端构建过程中的大部分重要任务。使用Gulp,再之前是 Grunt。 Gulp和Grunt很好用,他们高效的自动完成了很多我之前需要手动完成的工作,帮助我更快的工作。但是我却开始觉得我在这些工具上花费的精力要比花在我自己代码上的精力多得多。

Grunt, Gulp, Broccoli, Brunch和类似的工具都需要将自己的任务配置的适合他们的范型和结构,这些工具每一个都需要学习他们不同的语法、奇怪的用法和特有的方法。这增加了编码复杂度、构建复杂度,使得你关注修复工具问题更甚于写代码

由于这些构建工具依赖于包装了核心命令行工具的插件,并基于这个核心工具做了进一步的抽象,这使得出错的情况变得更加复杂。

以下三个问题我已经遇到过多次:

  • 如果当前的命令行工具中没有你想用的插件,那么你将束手无策(除非你自己写一个)。
  • 你要用的插件包装了旧版的工具,所以使用的插件和当前核心工具的特性、文档不能够完全匹配一致。
  • 错误提示不够友好。如果插件挂了的话,很可能没法一路追踪这个错误直到核心工具,这时我很沮丧的发现自己并不清楚如何debug这个错误。

但是,请记住...

如果你对当前的构建系统很满意,并且它能够很好的完成你的需求的话,就请继续使用吧!不要因为npm scripts越来越流行就盲目的使用它,应该把精力集中在写代码而不是学习更多的工具。如果你开始觉得自己正在和使用的工具战斗,那么这个时候我建议你考虑使用一下npm scripts。

如果你现在做好决定想要调研或使用npm scripts,那么请继续阅读本文!本文将会提供大量的案例任务,同时基于这些任务我也创建了npm-build-boilerplate 以方便你学习。那么下面让我们开始吧!

写npm scripts

我们会花费大量的时间在`package.json`文件上。这个文件描述了我们需要的所有的依赖脚本。以下是我的boilerplate项目中的一部分内容:

复制代码

 1 {
 2   "name": "npm-build-boilerplate",
 3   "version": "1.0.0",
 4   "scripts": {
 5     ...
 6   },
 7   "devDependencies": {
 8     ...
 9   }
10 }

 

接下来我们将逐步创建`package.json`文件。我们的脚本会写入scripts对象中,所有我们要使用的工具都会被安装并且写入devDependencies对象中。在开始之前,以下是本文中的项目结构:

编译scss为css

我是SCSS的重度用户,平时工作都依赖SCSS。为了将SCSS编译成CSS,我使用了node-sass。首先,我们需要安装node-sass,在命令行下运行以下代码:

npm install --save-dev node-sass

这个命令会在当前目录下安装node-sass,并添加到`package.json`的devDependencies对象中。当其他人使用你的项目时会非常方便,因为他们已经有了运行项目所需的所有内容。只要安装过一次,使用时在命令行运行以下代码即可:

node-sass --output-style compressed -o dist/css src/scss
让我们看一下这个命令做了什么:从后向前看,查找`src/scss`目录的SCSS文件,输出(-o 标识)编译的CSS到`dist/css`目录,压缩输出文件(使用 --output-style 标识,设置选项值为"compressed")。

现在我们知道了在命令行中如何工作,那么让我们把它放到npm scirpt中。在`package.json`的scripts对象中添加如下内容:

"scripts": {
  "scss": "node-sass --output-style compressed -o dist/css src/scss"
}
现在回到命令行并运行:
npm run scss
可以看到这样运行的输出结果和直接在命令行使用node-sass命令得到的结果一致。

本文剩余部分创建的任何一个npm script,都可以像上例一样使用命令行运行。

只要把你想要运行的任务名从scss替换成你想要的名字即可。

As you will see, many of the command line tools we'll use have numerous options you can use to configure it exactly you see fit. For instance, here's the list of (node-sass options). Here's a different setup show how to pass multiple options:

你将看到,我们使用的很多命令行工具都有很多的配置项,你可以使用配置项来精确完成你想要做的工作。比如,这是node-sass的选项列表,以下展示了传多个配置项的配置方法:

"scripts": {
  "scss": "node-sass --output-style nested --indent-type tab --indent-width 4 -o dist/css src/scss"
}

使用PostCSS自动给CSS加前缀

我们已经能够把SCSS编译成CSS,现在我们希望通过Autoprefixer和PostCSS自动给CSS代码添加厂商前缀,我们可以通过空格分隔的方式从而同时安装多个模块:

npm install --save-dev postcss-cli autoprefixer
因为PostCSS默认不做任何事情,所以我们安装了两个模块。PostCSS依赖其他的插件来处理你提供的CSS,比如Autoprefixer。

安装并保存必要工具到devDependencies后,在你的scripts对象中添加一个新任务:

"scripts": {
  ...
  "autoprefixer": "postcss -u autoprefixer -r dist/css/*"
}

这个任务的意思是:嗨postcss,使用(-u标识符)Autoprefixer替换(-r标识符)`dist/css`目录下的所有`.css`文件,给他们添加厂商前缀代码。就是这样简单!想要修改默认浏览器前缀?只要给脚本添加如下代码即可:

"autoprefixer": "postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*"
再次申明,配置你自己的构建代码有很多选项可以使用:postcss-cliautoprefixer
 

JavaScript 代码检查

对于写代码来说,保持标准格式和样式是非常重要的,它能够确保错误最小化并提高开发效率。"代码检查"帮助我们自动化的完成了这个工作,所以我们通过使用 eslint 来进行代码检查。

再次如上文所述,安装eslint的包,这次让我们使用快捷方式:

npm i -D eslint

这和如下代码是一样的效果:

npm install --save-dev eslint
安装完成后,我们给eslint配置一些运行代码的基本规则。使用如下代码开始一个向导:
eslint --init // 注:这里直接使用会抛错eslint找不到,因为这种使用方法必须安装在全局,即通过 npm install i -g eslint方式安装
我建议选择"回答代码风格问题"并回答提问的相关问题。这个过程中eslint会在你的项目根目录下生成一个新文件,并检测你的相关代码。

现在,让我们把代码风格检测任务添加到`package.json`的scripts对象中:

"scripts": {
  ...
  "lint": "eslint src/js"
}

我们的任务仅有13字符!它会查找`src/js`目录下的所有JavaScript文件,并根据刚才生成的规则进行代码检测。当然,如果感兴趣的话你可以详细配置各种规则:get crazy with the options

混淆压缩JavaScript文件

让我们继续,下面我们需要使用uglify-js来混淆压缩JavaScript文件,首先需要安装uglify-js:

npm i -D uglify-js
然后我们可以在`package.json`里创建压缩混合任务:
"scripts": {
  ...
  "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js"
}

npm scripts的任务的本质是:可以重复执行的、命令行任务的快捷方式(别名),这也是npm scripts的优点之一。这就意味着你可以直接在脚本里使用标准命令行代码!这个任务使用了两个标准命令行特性:mkdir 和 &&。

这个任务的第一部分“ mkdir -p dist/js ”:如果不存在目录(-p标识)就创建一个目录结构(mkdir),创建成功后执行uglifyjs命令。&&帮助你连接多个命令,如果前一个命令成功执行的话,就分别顺序执行剩余的命令。

这个任务的第二部分告诉uglifyjs针对`src/js/`目录下的所有JS文件(`*.js`),使用"mangle"命令(-m 标识),输出结果到`dist/js/app.js`文件中。这里是uglifyjs工具的全部配置选项 list of options

让我们来更新一下uglify任务,创建一个`dist/js/app.js`的压缩版本,链接另外一个uglifyjs的命令并传参给"compress"(-c标识)。

"scripts": {
  ...
  "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js && uglifyjs src/js/*.js -m -c -o dist/js/app.min.js"
}

压缩图片

下面我们将进行图片压缩的工作。根据httparchive.org的数据统计,网络上前1000名的网站平均页面大小为1.9M,其中图片占了1.1M(with images accounting for 1.1mb of that total)。所以提高网页加载速度的其中一个好办法就是减小图片大小。

安装 imagemin-cli:

npm i -D imagemin-cli
Imagemin非常棒,它可以压缩大多数图片类型,包括GIF、JPG、PNG和SVG。 使用如下代码可以将一整个文件夹的图片全部压缩:
"scripts": {
  ...
  "imagemin": "imagemin src/images dist/images -p",
}

这个任务告诉imagemin找到并压缩`src/images`中的所有图片并输出到`dist/images`中。-p标志在允许的情况下将图片处理成渐进图片。更多配置可查看文档 all available options

SVG精灵(Sprites)

关于SVG的讨论近年来逐渐火热,SVG有众多优点:在所有的设备上保持松散结构、可通过CSS编辑、对读屏软件友好。然而,SVG编辑软件经常会产生大量的冗余代码。幸运的是,svgo可以帮助你自动删除这些冗余信息(我们马上就会安装svgo)。

接下来我们来安装svg-sprite-generator,用于自动处理并整合多个SVG文件为一个SVG文件(更多处理方案:more on that technique here)。

npm i -D svgo svg-sprite-generator

你现在应该已经熟悉了这个过程——添加一个任务在你的`package.json`scripts对象中:

"scripts": {
  ...
  "icons": "svgo -f src/images/icons && mkdir -p dist/images && svg-sprite-generate -d src/images/icons -o dist/images/icons.svg"
}

注意icons任务通过两个&&引导符做了三件事情: 1.使用svgo传参一个SVG目录(-f标识),这个操作压缩了目录内的全部SVG文件;2.如果不存在'dist/images'目录则创建该目录(使用mkdir -p命令);3.使用svg-sprite-generator,传参一个SVG目录(-d标识)以及输出处理后的SVG文件的目录路径名(-o标识)。

通过BrowserSync提供服务、自动监测并注入变更

最后一个插件是BrowserSync,它可以做如下事情:启动一个本地服务,向连接的浏览器自动注入更新的文件,并同步浏览器的点击和滚动。安装并添加任务的代码如下:

npm i -D browser-sync
"scripts": {
  ...
  "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'"
}

BrowserSync任务默认使用当前根目录下的路径启动一个服务器(--server标识),--files标识告诉BrowserSync去监测`dist`目录的CSS或JS文件,一旦有任何变化,则自动向页面注入变化的文件。

你可以同时打开多个浏览器(甚至在不同的设备上),他们都会实时更新文件变化的!

分组任务

使用以上任务我们可以做到如下功能:

  • 编译SCSS到CSS并自动添加厂商前缀
  • 对Javascript进行代码检查及混淆压缩
  • 压缩图片
  • 整合整个文件夹内的SVG文件为一个SVG文件
  • 启动一个本地服务并向连接至该服务的浏览器自动注入更新。

这还不是全部内容!

合并CSS任务

Let's add a task that combines the two CSS related tasks (preprocessing Sass and running Autoprefixer), so we don't have to run each one separately:

我们会添加一个新的任务,用于合并两个CSS相关的任务(处理SASS和执行加前缀的Autoprefixer),有了这个任务我们就不用分别执行两个相关任务了:

"scripts": {
  ...
  "build:css": "npm run scss && npm run autoprefixer"
}

当你运行npm run build:css时,这个任务会告诉命令行去执行npm run scss,当这个任务成功完成后,会接着(&&)执行 npm run autoprefixer。

就像这个build:css任务一样,我们可以把JavaScript任务也链接到一起以方便执行:

合并JavaScript任务

"scripts": {
  ...
  "build:js": "npm run lint && npm run uglify"
}

现在,我们可以通过npm run build:js一步调用,来进行代码检测、混淆压缩JavaScript代码了!

合并剩余任务

对于图片任务、其他剩余构建任务,我们可以用相同的方法把他们变成一个任务:

"scripts": {
  ...
  "build:images": "npm run imagemin && npm run icons",
  "build:all": "npm run build:css && npm run build:js && npm run build:images",
}

变更监控

至此,我们的任务不断的需要对文件做一些变更,我们不断的需要切回命令行去运行相应的任务。针对这个问题,我们可以添加一个任务来监听文件变更,让文件在变更的时候自动执行这些任务。这里我推荐使用onchange插件,安装方法如下:

npm i -D onchange
让我们来给CSS和JavaScript设置监控任务:
"scripts": {
  ...
  "watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",
  "watch:js": "onchange 'src/js/*.js' -- npm run build:js",
}

这些任务可以分解如下:onchange需要你传参想要监控的文件路径(字符串),这里我们传的是SCSS和JS源文件,我们想要运行的命令跟在--之后,这个命令当路径内的文件发生增删改的时候就会被立即执行。

让我们再添加一个监控命令来完成我们的npm scripts构建过程。

再添加一个包,parallelshell

npm i -D parallelshell
再次给scriopts对象添加一个新任务:
"scripts": {
  ...
  "watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'"
}

parallelshell支持多个参数字符串,它会给npm run传多个任务用于执行。

为什么时候parallelshell去合并多个任务,而不是像之前的任务一样使用&&呢?最开始我也尝试这么做了,但是问题是:&&链接多个命令到一块,需要等待每一个命令成功完成后才会执行下一个任务。然而当我们运行watch命令时,这些命令一直都不会结束!这样我们就会卡在一个无限循环里。

因此,使用parallelshell使得我们可以同时执行多个watch命令。(译者注:后来在评论里有人推荐使用npm-run-all插件来代替parallelshell,它支持这种用法可以一次性检测全部watch任务更加方便:"watch": "npm-run-all --parallel serve watch:*")

这个任务使用了BrowserSync的npm run serve任务启动了一个服务,然后对CSS和JavaScript文件执行了监控命令,一旦CSS或JavaScript文件有变更,监控任务就会执行相应的构建(build)任务。由于BrowserSync被设置成监控`dist`目录下的变更,所以它会自动的向相关联的URL内注入新的文件,真是太棒了!

其他实用任务

npm有大量可以实用的插件(ots of baked in tasks ),让我们再添加一个新的任务来看看这些插件对构建脚本的影响:

"scripts": {
  ...
  "postinstall": "npm run watch:all"
}

当你在命令行中执行npm install的时候postinstall会立即执行,当团队合作时这个功能非常有用。当别人复制了你的项目并运行了npm install的时候,我们的watch:all任务就会马上执行,别人马上就会准备好一切开发环境:启动一个服务、打开一个浏览器窗口、监控文件变更。

打包

我通过本文学习了一些使用npm scripts构建过程和常用命令行的方法。希望对你也有帮助!

版权声明:本文为weixin_42693104原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42693104/article/details/81510566

智能推荐

1264页面推荐(中等 union all )稍微的难点在于找1的朋友

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200904233840843.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTMxNTk0,size_16,color_FFFFFF,t...

单链表+单链表代码(链表最基础)

链表 链表是有顺序的表,在内存中存储: 链表是以节点的方式存储的 每个节点包括data域,next域:指向下一个节点 如图:发现链表的各个节点不一定是连续存放的,有跳跃的,不是连续存储 链表分为带头节点的链表和没有头结点的链表 添加: 1.先创建一个head头结点,作用就是单链表的头 2.后面每添加一个节点,就直接加入到链表最后 遍历: 代码 添加节点到链表里: 这里借助于temp节点,通过循环找...

Rtthread学习笔记(十三)RT-Thread Studio开启硬件看门狗Watchdog

一、开启硬件看门狗Watchdog 1、配置RT-Thread Settings 2、开启stm32f1xx_hal_conf.h中的宏定义 3.使用RT接口函数初始化硬件看门狗...

TYVJ 4864 天天去哪吃 || 清北学堂金秋杯大奖赛

题目描述: 记录一下i这个值上次出现的位置在哪里,就是pre...

java反编译

jvm 把Boolean类型的值flag当做int类型处理。​​​ Foo.java: 由 class 文件生成 jasm 文件:java -jar asmtools.jar jdis Foo.class > Foo.jasm  修改jasm文件: 执行反编译: java -jar jd-gui-1.6.6.jar File 打开Foo.class文件:b修改为2 重新执行java...

猜你喜欢

【学习笔记】03-v-html的学习和示例

v-html的认识和使用 示例: 显示结果: 注意:v-html是有复制的...

Java实现在线考试系统(系统介绍)

1.和现在有的考试系统有以下几种优势: a.和现在有的系统比较起来,本系统有科目、章节、老师、学生、班级等信息的管理,还有批阅试卷查看已批阅试卷等。传统的考试系统划分并不细,业务功能简单。 b.和学校的考试系统还有外面的考试系统比较起来,本系统是B/S结构,学校的考试系统一般为C/S结构,性能方面不如B/S结构,并且C/S接口需要安装客户端,客户端压力很大,我的系统只需要电脑具有浏览器,在同一局域...

计算机视觉--多视几何初步尝试

基础矩阵的原理 K和K’分别是两个相机的参数矩阵。p和p’是X在平面π的坐标表示。所以可以得出 具体计算过程 代码: #!/usr/bin/env python coding: utf-8 from PIL import Image from numpy import * from pylab import * import numpy as np from imp ...

java初学者怎么学习才可以快速入门

java初学者怎么学习才可以快速入门 一、了解JAVA 我们要知道:Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言。 Java之父:詹姆斯·高斯林 1.1 java的三个体系 Java SE(Java Platform Standard Edition)。Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境...

字段属性之主键&增删改查&自增长&唯一键约束

字段属性之主键&自增长&唯一键约束 主键 主键:primary key 主要的键 一张表中只有一个字段可以使用对应的键,用来唯一的约束该字段里面的数据,不能重复,这种称之为主键 一张表只能最多一个主键 增加主键 SQL操作中有多种方式增加主键大体分为三种 1.在创建表的时候直接在字段之后跟primary key关键字(主键本身不允许为空) 优点:非常直接:缺点:只能使用一个字段作为...