经由历程这个教程进修怎样运用JavaScript打包东西Rollup合营PostCSS来庖代Grunt或Gulp处置惩罚款式文件。
上一篇文章中,我们完成了运用Rollup打包前端JavaScript入门。
这篇文章包括Part II
和Part III
。
Part II会继承在上次的项目中举行,为Rollup增添处置惩罚款式的才能,运用PostCSS举行一些转换,让我们能运用更简朴的变量写法和嵌套划定规矩等语法糖。
然后完成Part III,圆满完毕。第三部份将为项目增添文件监听和LiveReload,如许每当文件变化时就不必再手动地打包bundle文件了。
准备事情
我们会在上周的项目基础上继承举行,因而假如你还没有看上一节,引荐你先看一下。
NOTE: 假如你没有项目标副本,你可以经由历程这条敕令克隆在Part I完毕这个状况下的项目:
git clone -b part-2-starter --single-branch https://github.com/jlengstorf/learn-rollup.git
Part II:怎样鄙人一代运用中运用Rollup.js: PostCSS
你可以轻松地处置惩罚CSS并注入到文档的head
中,这取决于你的项目怎样设置,也是Rollup另一个长处。
别的,一切的构建历程都在一个处所,降低了开辟流程的复杂度 – 这对我们很有协助,尤其是在团队合作时。
不过蹩脚的是,我们使得款式依靠JavaScript,而且在无款式HTML在款式注入前会发生一个短暂的闪灼。这对有些项目来说是没法接收的,而且应当经由历程像运用PostCSS提取等体式格局处理。
既然这篇文章是关于Rollup的,那末:来吧。让我们运用Rollup!
STEP 0: 在main.js
中加载款式。
假如你之前历来没用过构建东西,可以觉得如许有点怪,但请随着我继承。为了在文档中运用款式,我们不会像寻常那样运用<link>
标签,取而代之,我们将在main.min.js
中运用import
语句。
如今在src/scripts/main.js
开首加载款式:
+ // Import styles (automatically injected into <head>).
+ import '../styles/main.css';
// Import a couple modules for testing.
import { sayHelloTo } from './modules/mod1';
import addArray from './modules/mod2';
// Import a logger for easier debugging.
import debug from 'debug';
const log = debug('app:log');
// The logger should only be disabled if we’re not in production.
if (ENV !== 'production') {
// Enable the logger.
debug.enable('*');
log('Logging is enabled!');
} else {
debug.disable();
}
// Run some functions from our imported modules.
const result1 = sayHelloTo('Jason');
const result2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${result1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${result2}`;
STEP 1: 装置PostCSS Rollup插件。
起首须要Rollup PostCSS插件,运用以下敕令装置:
npm install –save-dev rollup-plugin-postcss
STEP 2: 更新rollup.config.js
.
然后,增添插件到rollup.config.js
:
// Rollup plugins
import babel from 'rollup-plugin-babel';
import eslint from 'rollup-plugin-eslint';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
+ import postcss from 'rollup-plugin-postcss';
export default {
entry: 'src/scripts/main.js',
dest: 'build/js/main.min.js',
format: 'iife',
sourceMap: 'inline',
plugins: [
+ postcss({
+ extensions: [ '.css' ],
+ }),
resolve({
jsnext: true,
main: true,
browser: true,
}),
commonjs(),
eslint({
exclude: [
'src/styles/**',
]
}),
babel({
exclude: 'node_modules/**',
}),
replace({
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
}),
(process.env.NODE_ENV === 'production' && uglify()),
],
};
看一下天生的bundle。
如今我们已可以处置惩罚款式了,可以看一下新天生的bundle,看看它是怎样事情的。
运转./node_modules/.bin/rollup -c
,然后看一下天生的build/js/main.min.js
,在文件开首几行,可以看到一个名叫__$styleInject()
的新函数:
function __$styleInject(css) {
css = css || '';
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
__$styleInject("/* Styles omitted for brevity... */");
简朴地说,这个函数创建了一个<style>
元素并设置款式,然后增添到文档的<head>
标签中。
就在这个函数声明的下方,可以看到经由历程传入款式挪用该函数,经由历程PostCSS输出。很酷,不是吗?
但如今这些款式并没有真正地被处置惩罚;PostCSS只是直接地传输了我们的款式。让我们增添一些须要的PostCSS插件,使得款式能在目标浏览器上事情。
STEP 3: 装置必要的PostCSS插件。
我爱PostCSS。我已摒弃LESS阵营了,当一切人都扬弃LESS时,我发明本身或多或少被影响到场了Sass阵营,厥后PostCSS涌现了我就异常开心肠去学。
我喜好它是因为它供应了部份在LESS和Sass中我喜好的功用 – 嵌套,简朴的变量 – 而且没有完整摒弃LESS和Sass中我以为诱人也风险的功用,比方逻辑运算。
我喜好它的插件形式,而不是一个叫做“PostCSS”的言语。我们可以只挑选真正须要的特征 – 更主要的是,我们可以移除不想要的特征。
因而在我们的项目里,只会运用到四个插件 – 两个是语法糖,一个用来在兼容旧浏览器的新CSS特征,一个用来紧缩,削减天生的款式文件大小。
postcss-simple-vars
— 可以运用Sass作风的变量(e.g.$myColor: #fff;
,color: $myColor;
)而不是冗杂的CSS语法(e.g.:root {--myColor: #fff}
,color: var(--myColor)
)。如许更简约;我更喜好较短的语法。postcss-nested
— 许可运用嵌套划定规矩。实际上我不必它写嵌套划定规矩;我用它简化BEM友爱的挑选器的写法而且分别我的区块,元素和润饰到单个CSS块。postcss-cssnext
— 这个插件集使得大多数当代CSS语法(经由历程最新的CSS规范)可用,编译后以至可以在不支持新特征的旧浏览器中事情。cssnano
— 紧缩,减小输出CSS文件大小。相当于JavaScript中对应的UglifyJS。
运用这个敕令装置插件:
npm install –save-dev postcss-simple-vars postcss-nested postcss-cssnext cssnano
STEP 4: 更新rollup.config.js
。
接下来,在rollup.config.js
引入PostCSS插件,在设置对象的plugins
属性上增添一个postcss
。
// Rollup plugins
import babel from 'rollup-plugin-babel';
import eslint from 'rollup-plugin-eslint';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
import postcss from 'rollup-plugin-postcss';
+ // PostCSS plugins
+ import simplevars from 'postcss-simple-vars';
+ import nested from 'postcss-nested';
+ import cssnext from 'postcss-cssnext';
+ import cssnano from 'cssnano';
export default {
entry: 'src/scripts/main.js',
dest: 'build/js/main.min.js',
format: 'iife',
sourceMap: 'inline',
plugins: [
postcss({
+ plugins: [
+ simplevars(),
+ nested(),
+ cssnext({ warnForDuplicates: false, }),
+ cssnano(),
+ ],
extensions: [ '.css' ],
}),
resolve({
jsnext: true,
main: true,
browser: true,
}),
commonjs(),
eslint({
exclude: [
'src/styles/**',
]
}),
babel({
exclude: 'node_modules/**',
}),
replace({
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
}),
(process.env.NODE_ENV === 'production' && uglify()),
],
};
NOTE: 在
cssnext()
中设置了{ warnForDuplicates: false }
是因为它和cssnano()
都运用了Autoprefixer,会致使一个正告。不必计算设置, 我们只须要知道它被实行了两次(在这个例子中没什么害处)而且取消了正告。
搜检<head>
中的输出内容。
插件装置完后,从新构建bundle文件。(./node_modules/.bin/rollup -c
),然后在浏览器中翻开build/index.html
。可以看到页面是有款式的,假如我们检察元素可以发明款式被注入到页面头部,紧缩简化,增添一切浏览器前缀和别的我们预期的长处:
款式被PostCSS处置惩罚并经由历程Rpllup注入
太棒了!我们如今具有非常牢靠的构建流程:JavaScript会被打包,无用的代码会被移除,输出文件是经由紧缩精简的,款式时经由历程PostCSS处置惩罚后注入到文档头部的。
但是,末了依旧存在一个痛点,每当我们做了一些修正后都不得不手动地从新构建。因而鄙人个部份,我们让Rollup监听文件的变化,每当有文件转变时就让浏览器自动从新载入文件。
Part III: 怎样鄙人一代运用中运用Rollup.js:及时加载
如今,我们的项目已可以打包JavaScript和款式文件了,但依旧是一个手动的历程。而且因为历程的每一个步骤都是手动的,比拟自动化流程失利风险更高 – 因为每次修正文件后都实行./node_modules/.bin/rollup -c
太痛苦了 – 我们愿望自动从新构建bundle。
NOTE: 假如你没有项目标副本,你可以经由历程这条敕令克隆在Part II完毕这个状况下的项目::
git clone -b part-3-starter --single-branch https://github.com/jlengstorf/learn-rollup.git
STEP 0: 为Rollup增添监听插件。
基于Node.js的监听器是很罕见的开辟东西。假如你之前运用过webpack,Grunt,Gulp或许其他构建东西会很熟悉。
监听器是在一个项目中运转的历程,当你修正了它监听的文件夹内的恣意文件时就会触发一个行动。关于构建东西而言,平常这个行动是触发从新构建。
在我们的项目中,我们须要监听src
目次下的任何文件,而且探测到文件变化后愿望Rollup从新打包。
为了到达目标,我们运用rollup-watch
插件,它和前面的别的Rollup插件有些差别 – but more on that in a bit。让我们先装置插件:
npm install --save-dev rollup-watch
STEP 1: 传入--watch
标识运转Rollup。
rollup-watch
与其他插件的差别就是运用这个插件不须要对rollup.config.js
做任何修正。
取而代之的是,在终端敕令中增添一个标识:
# Run Rollup with the watch plugin enabled
./node_modules/.bin/rollup -c --watch
运转完后,可以发明控制台的输出和之前有点差别:
$ ./node_modules/.bin/rollup -c --watch
checking rollup-watch version...
bundling...
bundled in 949ms. Watching for changes...
这个历程依旧坚持运动状况,正在监听变化。
假如我们在src/main.js
做点小变化 – 比方加一条诠释 – 在我们保留修正的那一刻新的bundle文件就天生了。
监听顺序实行时,变化会触发从新构建。LINTER会马上捕捉毛病。很文雅,不是吗?
这为我们在开辟历程当中节省了大批时候,不过还可以更进一步。如今我们依旧须要手动革新浏览器来猎取更新后的bundle – 增添一个东西,在bundle更新后自动革新浏览器。
TIP: 在终端窗口输入
control + C
完毕监听历程。
STEP 2: 装置Liveload自动革新浏览器。
LiveReload是加快开辟的常用东西。它是一个跑在背景的历程,每当有它监听的文件变化时,他就会关照浏览器革新。
先下载插件:
npm install --save-dev livereload
STEP 3: 注入livereload剧本。
In src/main.js
, add the following:
在LiveReload事情前,须要向页面中注入一段剧本用于和LiveReload的服务器竖立衔接。
不过只要开辟环境下有这个需求,应用环境变量的才能推断只要在非生产环境下才注入剧本。
在src/main.js
中增添下面代码:
// Import styles (automatically injected into <head>).
import '../styles/main.css';
// Import a couple modules for testing.
import { sayHelloTo } from './modules/mod1';
import addArray from './modules/mod2';
// Import a logger for easier debugging.
import debug from 'debug';
const log = debug('app:log');
// The logger should only be disabled if we’re not in production.
if (ENV !== 'production') {
// Enable the logger.
debug.enable('*');
log('Logging is enabled!');
+ // Enable LiveReload
+ document.write(
+ '<script src="http://' + (location.host || 'localhost').split(':')[0] +
+ ':35729/livereload.js?snipver=1"></' + 'script>'
+ );
} else {
debug.disable();
}
// Run some functions from our imported modules.
const result1 = sayHelloTo('Jason');
const result2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${result1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${result2}`;
做一些修正然后保留,如今我们碰运气。
NOTE: Livereload是怎样事情的并不主要,简朴的诠释就是敕令行历程监听文件变化,然后经由历程websockets向客户端剧本发送音讯触发重加载。
STEP 4: 运转Livereload。
LiveReload装置好而且剧本注入到文档中后,我们可以运转它去监听build
目次:
./node_modules/.bin/livereload 'build/'
NOTE: 监听
build/
是因为我们只须要在新的bundle发生时才从新构建。
输出效果像下面如许:
$ ./node_modules/.bin/livereload 'build/'
Starting LiveReload v0.5.0 for /Users/jlengstorf/dev/code.lengstorf.com/projects/learn-rollup/build on port 35729.
假如我们用浏览器翻开build/index.html
– 务必在开启LiveReload后再革新页面,确保socket衔接处于激活状况 – 可以发明build/index.html
的变化会让浏览器自动从新加载:
文件变化触发浏览器从新加载。
异常棒,但依旧不圆满:如今我们只能运转Rollup的监听函数或许LiveReload,除非我们翻开多个终端会话。这可不抱负。接下来我们会挑选一个处理办法。
STEP 5: 运用package.json
剧本简化启动历程。
教程至今,我们都不得不输入rollup
剧本的全途径,我猜你已觉得到这很蠢了。
因而我们须要一个能同时运转监听使命和Livereload
的东西,先将这两个rollup
敕令和LiveReload敕令当作剧本写在package.json
中。
翻开package.json
– 它位于项目根目次。在这个文件里能看到以下内容:
{
"name": "learn-rollup",
"version": "0.0.0",
"description": "This is an example project to accompany a tutorial on using Rollup.",
"main": "build/js/main.min.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/jlengstorf/learn-rollup.git"
},
"author": "Jason Lengstorf <jason@lengstorf.com> (@jlengstorf)",
"license": "ISC",
"bugs": {
"url": "https://github.com/jlengstorf/learn-rollup/issues"
},
"homepage": "https://github.com/jlengstorf/learn-rollup#readme",
"devDependencies": {
"babel-preset-es2015-rollup": "^1.2.0",
"cssnano": "^3.7.4",
"livereload": "^0.5.0",
"npm-run-all": "^3.0.0",
"postcss-cssnext": "^2.7.0",
"postcss-nested": "^1.0.0",
"postcss-simple-vars": "^3.0.0",
"rollup": "^0.34.9",
"rollup-plugin-babel": "^2.6.1",
"rollup-plugin-commonjs": "^3.3.1",
"rollup-plugin-eslint": "^2.0.2",
"rollup-plugin-node-resolve": "^2.0.0",
"rollup-plugin-postcss": "^0.1.1",
"rollup-plugin-replace": "^1.1.1",
"rollup-plugin-uglify": "^1.0.1",
"rollup-watch": "^2.5.0"
},
"dependencies": {
"debug": "^2.2.0"
}
}
看到scripts
属性了吗?我们将为它增添两个新属性:
一个运转Rollup打包的剧本(本来手动实行的
./node_modules/.bin/rollup -c --watch
)一个启动LiveReload的剧本(本来手动实行的
./node_modules/.bin/livereload 'build/'
)
在package.json
加上下面的内容:
{
"name": "learn-rollup",
"version": "0.0.0",
"description": "This is an example project to accompany a tutorial on using Rollup.",
"main": "build/js/main.min.js",
"scripts": {
+ "dev": "rollup -c --watch",
+ "reload": "livereload 'build/'",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/jlengstorf/learn-rollup.git"
},
"author": "Jason Lengstorf <jason@lengstorf.com> (@jlengstorf)",
"license": "ISC",
"bugs": {
"url": "https://github.com/jlengstorf/learn-rollup/issues"
},
"homepage": "https://github.com/jlengstorf/learn-rollup#readme",
"devDependencies": {
"babel-preset-es2015-rollup": "^1.2.0",
"cssnano": "^3.7.4",
"livereload": "^0.5.0",
"npm-run-all": "^3.0.0",
"postcss-cssnext": "^2.7.0",
"postcss-nested": "^1.0.0",
"postcss-simple-vars": "^3.0.0",
"rollup": "^0.34.9",
"rollup-plugin-babel": "^2.6.1",
"rollup-plugin-commonjs": "^3.3.1",
"rollup-plugin-eslint": "^2.0.2",
"rollup-plugin-node-resolve": "^2.0.0",
"rollup-plugin-postcss": "^0.1.1",
"rollup-plugin-replace": "^1.1.1",
"rollup-plugin-uglify": "^1.0.1",
"rollup-watch": "^2.5.0"
},
"dependencies": {
"debug": "^2.2.0"
}
}
这些剧本让我们可以运用简称来实行挑选的剧本。
运用npm run dev
运转Rollup。
运用npm run reload
实行LiveReload。
接下来要做的就是让他们一同运转。
STEP 6: 装置同时运转watcher和Livereload的东西。
为了能同时实行Rollup和LiveReload,我们要运用一个叫做npm-run-all
的东西。
这是一个壮大的东西,我们先不议论他的悉数功用。我们如今只运用它并行实行剧本的才能 – 意味着同一个终端会话可以同时实行两个使命。
先装置npm-run-all
:
npm install --save-dev npm-run-all
然后我们要在package.json
中再到场一条挪用npm-run-all
的剧本。在scripts
代码块内,增添以下内容(简朴起见我省略了文件的大部份内容):
"scripts": {
"dev": "rollup -c --watch",
"reload": "livereload 'build/' -d",
+ "watch": "npm-run-all --parallel reload dev",
"test": "echo \"Error: no test specified\" && exit 1"
}
保留修正,切换到终端。准备好末了一步!
STEP 7: 实行末了的watch
剧本。
就像之前做的一样。
在终端中运转下面的敕令:
npm run watch
然后革新浏览器, 转变一下JS或CSS, 浏览器会加载更新后的bundle并自动革新 – 太巧妙了!
Liveload + 自动构建犹如魔法平常。
如今我们是Rollup专家了。我们的打包代码变得更小更快,开辟流程也更轻松疾速。
Further Reading
拓展浏览
Some discussion about using JS to insert styles, and when/whether it’s appropriate
这篇文章的代码放在GitHub上。你可以fork 这个堆栈举行修正或测试,开issue或许报告bug,或许新建pull request举行发起或许修正。