百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

深入学习rollup来进行打包(rollup打包react)

wxin55 2024-10-25 18:07 23 浏览 0 评论

深入学习rollup来进行打包

阅读目录

  • 一:什么是Rollup?
  • 二:如何使用Rollup来处理并打包JS文件?
  • 三:设置Babel来使旧浏览器也支持ES6的代码
  • 四:添加一个debug包来记录日志
  • 五:添加插件来替代环境变量
  • 六:添加 UglifyJS来压缩我们js的代码
  • 七:监听文件变化的插件 --- rollup-watch
  • 八:开启本地服务的插件 --- rollup-plugin-serve
  • 九:实时刷新页面 --- rollup-plugin-livereload
  • 十. 安装同时运行watcher 和 Livereload的工具
  • 十一. rollup+PostCSS打包样式文件并添加 LiveReload

回到顶部

一:什么是Rollup?

rollup是一款用来es6模块打包代码的构建工具(支持css和js打包)。当我们使用ES6模块编写应用或者库时,它可以打包成一个单独文件提供浏览器和Node.js来使用。

它的优点有如下

1. 能组合我们的脚本文件。

2. 移除未使用的代码(仅仅使用ES6语法中)。

3. 在浏览器中支持使用 Node modules。

4. 压缩文件代码使文件大小尽可能最小化。

Rollup最主要的优点是 它是基于ES2015模块的,相比于webpack或Browserify所使用的CommonJS模块更加有效率,因为Rollup使用一种叫做

tree-shaking的特性来移除模块中未使用的代码,这也就是说当我们引用一个库的时候,我们只用到一个库的某一段的代码的时候,它不会把所有的代码打包进来,而仅仅打包使用到的代码(webpack2.0+貌似也引入了tree-shaking)。

注意:Rollup只会在ES6模块中支持tree-shaking特性。目前按照CommonJS模块编写的jquery不能被支持tree-shaking.

rollup 的应用场景

现在目前流行的打包有 gulp 和 webpack,那么与前面两个对比,我觉得rollup更适合打包js库,但是对于打包一个项目的整个应用的话,我到觉得webpack更适合,比如打包一些图片,字体等资源文件的时候,webpack很适合,目前貌似没有看到rollup可以做到这些。

之所以我来研究rollup,是因为最近在看vuex的源码的时候,看到它的js库就是使用rollup来进行打包的。

回到顶部

二:如何使用Rollup来处理并打包JS文件?

2-1 安装Rollup并创建配置文件,通过如下命令安装:

进入项目根目录后,运行命令: npm install --save-dev rollup

2-2 在项目的根目录下新建一个新文件 rollup.config.js, 之后再在文件中添加如下代码:

export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 }
}

下面再来了解一下各个配置的含义:

input: rollup先执行的入口文件。

output:rollup 输出的文件。

output.format: rollup支持的多种输出格式(有amd,cjs, es, iife 和 umd, 具体看 http://www.cnblogs.com/tugenhua0707/p/8150915.html)

sourceMap —— 如果有 sourcemap 的话,那么在调试代码时会提供很大的帮助,这个选项会在生成文件中添加 sourcemap,来让事情变得更加简单。

我们在package.json代码下 添加如下脚本。

"scripts": {
 "build": "rollup -c"
}

因此我们只要在命令行中 输入命令:npm run build 即可完成打包;

我们再看下各个文件下的代码:

src/js/a.js 代码如下:

export function a(name) {
 const temp = `Hello, ${name}!`;
 return temp;
}
export function b(name) {
 const temp = `Later, ${name}!`;
 return temp;
}

src/js/b.js代码如下:

/**
 * Adds all the values in an array.
 * @param {Array} arr an array of numbers
 * @return {Number} the sum of all the array values
 */
const addArray = arr => {
 const result = arr.reduce((a, b) => a + b, 0);
 return result;
};
export default addArray;

src/main.js代码如下:

import { a } from './js/a';
import addArray from './js/b';
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
console.log(res1);
console.log(res2);

最终会在项目的根目录下生成文件 dist/js/main.min.js, 代码如下:

(function () {
'use strict';
function a(name) {
 const temp = `Hello, ${name}!`;
 return temp;
}
/**
 * Adds all the values in an array.
 * @param {Array} arr an array of numbers
 * @return {Number} the sum of all the array values
 */
const addArray = arr => {
 const result = arr.reduce((a, b) => a + b, 0);
 return result;
};
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
console.log(res1);
console.log(res2);
}());

如上可以看到 在 src/js/a.js 下的 b函数没有被使用到,所以打包的时候没有被打包进来。

注意:在上面代码打包后,只有现代浏览器会正常工作,如果要让不支持ES2015的旧版本浏览器下也正常工作的话,我们需要添加一些插件。

回到顶部

三:设置Babel来使旧浏览器也支持ES6的代码

如上打包后的代码,我们可以在现代浏览器下运行了,但是如果我们使用老版本的浏览器的话,就会产生错误。幸运的是,Babel已经提供了支持。

我们首先需要安装一些依赖项如下命令:

npm install --save-dev 
babel-core babel-preset-env babel-plugin-external-helpers 
babel-plugin-transform-runtime babel-preset-stage-2 
babel-register rollup-plugin-babel

注意:Babel preset 是一个有关Babel插件的集合,它会告诉Babel我们需要转译什么。

3.2 创建 .babelrc文件

接下来需要在项目的根目录下创建 .babelrc的新文件了,它内部添加如下JSON代码:

{
 "presets": [
 ["env", {
 "modules": false,
 "targets": {
 "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
 }
 }],
 "stage-2"
 ],
 "plugins": ["transform-runtime", "external-helpers"] // 配置runtime,不设置会报错
}

它会告诉Babel应该使用哪种preset来转译代码。

因此我们再更新下 rollup.config.js,我们需要Babel插件,将它添加到一个新的配置选项plugins中,他会管控一个数组形式的插件列表,代码如下:

// Rollup plugins
import babel from 'rollup-plugin-babel';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 babel({
 exclude: 'node_modules/**' // 排除node_module下的所有文件
 })
 ]
}

为了避免转译第三方脚本,我们需要设置一个 exclude 的配置选项来忽略掉 node_modules 目录下的所有文件。安装完成后,我们重新运行命令;然后打包后代码变成如下:

(function () {
'use strict';
function a(name) {
 var temp = "Hello, " + name + "!";
 return temp;
}
/**
 * Adds all the values in an array.
 * @param {Array} arr an array of numbers
 * @return {Number} the sum of all the array values
 */
var addArray = function addArray(arr) {
 var result = arr.reduce(function (a, b) {
 return a + b;
 }, 0);
 return result;
};
var res1 = a('kongzhi');
var res2 = addArray([1, 2, 3, 4]);
console.log(res1);
console.log(res2);
}());

我们对比下代码,可以看到 addArray 的箭头函数解析成真正的函数了。 在转译运行完成后,代码也差不多一样的,只是代码已经支持

了IE9之前的浏览器了。

注意: Babel也提供了 babel-polyfill, 也可以让IE8之前的浏览器能够顺利执行。

回到顶部

四:添加一个debug包来记录日志

为了查看日志,我们将在代码中添加一个debug包来记录下日志信息。通过如下命令安装:

npm install --save debug

然后我们可以在 src/main.js中,添加一些简单的日志记录:如下代码:

import { a } from './js/a';
import addArray from './js/b';
import debug from 'debug';
const log = debug('app:log');
// Enable the logger.
debug.enable('*');
log('Logging is enabled!');
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;

index.html 代码变成如下:

<!doctype html>
<html lang="en">
<head>
 <meta charset="utf-8">
 <meta name="viewport"
 content="width=device-width,minimum-scale=1,initial-scale=1">
 <title>Learning Rollup</title>
</head>
<body>
 <h1>Learning Rollup</h1>
 <p>
 Let’s learn how to use <a href="http://rollupjs.org/">Rollup</a>.
 </p>
 <!-- JS-generated output will be added here. -->
 <pre class="debug"><code class="debug__output"></code></pre>
 <!-- This is the bundle generated by rollup.js -->
 <script src="./dist/js/main.min.js"></script>
</body>
</html>

然后我们直接访问index.html后,浏览器控制台报错了,错误信息如下:

Uncaught ReferenceError: debug is not defined,然后我们可以继续查看,打包后的main.min.js的代码变为如下:

(function (debug) {
'use strict';
debug = debug && debug.hasOwnProperty('default') ? debug['default'] : debug;
function a(name) {
 var temp = "Hello, " + name + "!";
 return temp;
}
/**
 * Adds all the values in an array.
 * @param {Array} arr an array of numbers
 * @return {Number} the sum of all the array values
 */
var addArray = function addArray(arr) {
 var result = arr.reduce(function (a, b) {
 return a + b;
 }, 0);
 return result;
};
var log = debug('app:log');
// Enable the logger.
debug.enable('*');
log('Logging is enabled!');
var res1 = a('kongzhi');
var res2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
var printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = 'sayHelloTo(\'Jason\') => ' + res1 + '\n\n';
printTarget.innerText += 'addArray([1, 2, 3, 4]) => ' + res2;
}(debug));

也就是说 浏览器报错是因为打包后的debug是 undefined,这是因为一般的情况下,第三方node模块并不会被Rollup正确加载。

Node模块使用的是CommonJS, 它不会被Rollup兼容因此不能直接被使用,为了解决这个问题,我们需要添加一些插件来

处理Node依赖和CommonJS模块。

为了解决上面的两个问题,我们需要在Rollup中添加如下两个插件:

1. rollup-plugin-node-resolve 该插件会允许加载在 node_modules中的第三方模块。

2. rollup-plugin-commonjs 它会将CommonJS模块转换为ES6来为Rollup获得兼容。

因此如下命令即可安装:

npm install --save-dev rollup-plugin-node-resolve rollup-plugin-commonjs

然后我们继续更新下 rollup.config.js 代码如下:

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 })
 ]
}

到目前为止一切顺利,但是当我们运行index.html时候, rollup 时我们会得到一个日志信息:

在控制台如下日志信息:

app:log Logging is enabled! +0ms

index.html 页面上显示如下:

Learning Rollup
Let’s learn how to use Rollup.
sayHelloTo('Jason') => Hello, kongzhi!
addArray([1, 2, 3, 4]) => 10

如上代码,我们看到引入了 rollup-plugin-json 插件了,该插件的作用是读取json信息的,比如我读取package.json的信息:

然后我把main.js中引入对应代码。代码如下:

import { a } from './js/a';
import addArray from './js/b';
import debug from 'debug';
// 添加json
import pkg from '../package.json';
console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0
const log = debug('app:log');
// Enable the logger.
debug.enable('*');
log('Logging is enabled!');
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;

在控制台输出如下信息:

控制台输出 running version 1.0.0

回到顶部

五:添加插件来替代环境变量

环境变量能为我们的开发流程提供很大的帮助,我们可以通过它来执行关闭或开启日志,注入开发环境脚本等功能。

因此我们可以在main.js中添加基础配置的ENV。让我们添加一个环境变量来使我们的日志脚本只在非 production环境下才会执行

。如下main.js代码:

import { a } from './js/a';
import addArray from './js/b';
import debug from 'debug';
// 添加json
import pkg from '../package.json';
console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0
const log = debug('app:log');
// 如果是正式环境的话,不输出日志信息
if (ENV !== 'production') {
 // Enable the logger.
 debug.enable('*');
 log('Logging is enabled!');
} else {
 debug.disable();
}
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;

然后打包完成后,在浏览器查看 发现报错了,如下错误信息:

Uncaught ReferenceError: ENV is not defined

这也很正常,因为我们并没有定义它,现在我们还需要一个插件来将我们的环境变量用到bundle中。

5-1 先安装 rollup-plugin-replcae,该插件是一个用来查找和替换的工作,我们只需要找到目前的环境变量并且使用实际

的值替代就可以了。先安装如下:

npm install --save-dev rollup-plugin-replace

然后我们再来更新一下 rollup.config.js, 配置是我们可以添加一个 key:value 的配对表,key值是准备被替换的键,而value是将要被替换的值。

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 }),
 replace({
 ENV: JSON.stringify(process.env.NODE_ENV || 'development')
 })
 ]
}

当我们现在运行 npm run build 的时候还是有日志信息的,因为默认的环境就是 development, 但是当我们在命令

行中使用如下命令:`NODE_ENV=production ./node_modules/.bin/rollup -c`(mac系统下的命令), 然后打包

后,刷新浏览器 就不会有日志记录信息了。

注意:在winodw环境下,运行如下命令: SET NODE_ENV=production ./node_modules/.bin/rollup -c

回到顶部

六:添加 UglifyJS来压缩我们js的代码

安装插件 rollup-plugin-uglify

命令如下安装:

npm install --save-dev rollup-plugin-uglify

再在 rollup.config.js 配置代码,为了在开发中使代码更具可读性,我们只在生产环境压缩代码:

rollup.config.js配置代码如下:

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 }),
 replace({
 ENV: JSON.stringify(process.env.NODE_ENV || 'development')
 }),
 (process.env.NODE_ENV === 'production' && uglify())
 ]
}

当我们在mac系统下运行命令 `NODE_ENV=production ./node_modules/.bin/rollup -c` 后,代码被压缩了,当我们运行

npm run build 的时候,代码未被压缩。

回到顶部

七:监听文件变化的插件 --- rollup-watch

如下安装命令:

npm install --save-dev rollup-watch

然后在package.json 中设置 scripts属性即可:

"scripts": {
 "dev": "rollup -c -w",
 "build": "rollup -c"
}

当我们在 src/main.js 代码下 加入一句代码后 : console.log(1122); 然后在浏览器下刷新下即可在控制台可以看到打印输出 1122这样的就可以监听到了。不需要重新打包即可。

回到顶部

八:开启本地服务的插件 --- rollup-plugin-serve

安装命令如下:

npm install --save-dev rollup-plugin-serve

在rollup.config.js 配置代码如下:

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
import serve from 'rollup-plugin-serve';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 }),
 replace({
 ENV: JSON.stringify(process.env.NODE_ENV || 'development')
 }),
 (process.env.NODE_ENV === 'production' && uglify()),
 serve({
 open: true, // 是否打开浏览器
 contentBase: './', // 入口html的文件位置
 historyApiFallback: true, // Set to true to return index.html instead of 404
 host: 'localhost',
 port: 10001
 })
 ]
}

然后重启命令 npm run build 就可以会自动打开 http://localhost:10001/ 页面了。

注意: 这边port配置的端口号是五位数,不是四位数。

回到顶部

九:实时刷新页面 --- rollup-plugin-livereload

命令安装如下:

npm install --save-dev rollup-plugin-livereload

注入LiveReload脚本

在LiveReload工作前,需要向页面中注入一段脚本用于和LiveReload的服务器建立连接。

在src/main.js 中加入如下一段代码:

// Enable LiveReload
document.write(
 '<script src="http://' + (location.host || 'localhost').split(':')[0] +
 ':35729/livereload.js?snipver=1"></' + 'script>'
);

src/main.js所有代码如下:

import { a } from './js/a';
import addArray from './js/b';
import debug from 'debug';
// 添加json
import pkg from '../package.json';
console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0
const log = debug('app:log');
// 如果不是正式环境的话,不输出日志信息
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();
}
const res1 = a('kongzhi');
const res2 = addArray([1, 2, 3, 4]);
console.log(1122)
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;

运行 LiveReload

LiveReload安装好并且脚本注入到文档中后,我们可以运行它去监听build目录:

如下命令:

./node_modules/.bin/livereload 'build/'

运行完成后 发现报错了 Error: listen EADDRINUSE :::35729;通过百度才发现端口被占用了,需要换端口,因此我直接把这个进程杀掉不就可以了,

首先我们先使用如下命令来查看下进程:

lsof -n -i4TCP:35729

看到信息如下:

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 1452 tugenhua 15u IPv6 0xb0e27d409cc55a1b 0t0 TCP *:35729 (LISTEN)

运行如下命令杀掉:

kill -9 1452

再在命令行输入 ./node_modules/.bin/livereload 'src/' 即可看到如下:

$ ./node_modules/.bin/livereload 'src/'
Starting LiveReload v0.6.3 for /Users/tugenhua/个人demo/vue1204/rollup-build/src on port 35729.

注意:./node_modules/.bin/livereload 'src/' 这句代码的含义是 监听src文件夹的文件,因此index.html内会

监听到,我们可以打开 src/index.html后,然后在index.html修改内容后,保存一下就可以看到页面会自动刷新内容了。

如上虽然改变 src/index.html的内容后会自动刷新页面,但是感觉每次 都需要输入 ./node_modules/.bin/livereload 'src/' 这么一段命令,有点麻烦,因此我们可以在 package.json 脚本中来简化这个过程,在package.json下scripts加上如下代码:

"scripts": {
 "dev": "rollup -c -w",
 "build": "rollup -c",
 "reload": "livereload 'src/'"
},

当我们在命令行中 运行 npm run reload 也可以监听到了。但是我们监听不到 src/js 或 src/css 下的文件的变化,

因为它不会自动打包,而只是监听src下的文件变化而已。但是我们又不能同时打开 watcher 和 Livereload,会报错端口被占用的情况。

因此我们需要看第10条来解决这个问题哦;

回到顶部

十. 安装同时运行watcher 和 Livereload的工具

为了能同时执行 Rollup和LiveReload, 我们需要使用一个叫做 npm-run-all 的工具。它的含义是一个终端可以执行多个任务。

安装命令如下:

npm install --save-dev npm-run-all

然后我们要在package.json中再加入一条调用npm-run-all的脚本。在scripts代码块内,添加如下内容:

"scripts": {
 "dev": "rollup -c -w",
 "build": "rollup -c",
 "reload": "livereload 'src/'",
 "watch": "npm-run-all --parallel dev"
},

watch 就是新增的。因此我们可以在终端运行 npm run watch命令了,然后刷新浏览器(http://localhost:10002/src/index.html),改变一下js或者css,浏览器会自动加载更新后的代码了。

回到顶部

十一. rollup+PostCSS打包样式文件并添加 LiveReload

1. 在main.js中加载样式: 在main.js 中加入如下代码:

// Import styles (automatically injected into <head>).
import './css/index.css';
所有的代码如下:
import './css/index.css';
import { a } from './js/a';
import addArray from './js/b';
import debug from 'debug';
// 添加json
import pkg from '../package.json';
console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0
const log = debug('app:log');
// 如果不是正式环境的话,不输出日志信息
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();
}
const res1 = a('kongzhi222');
const res2 = addArray([1, 2, 3, 4]);
console.log(11222211)
// Print the results on the page.
const printTarget = document.getElementsByClassName('debug__output')[0];
printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`;
printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;

2. 安装PostCss插件

首先需要安装Rollup版本的PostCss插件,使用命令如下安装:

npm install --save-dev rollup-plugin-postcss

然后 添加插件到 rollup.config.js中去:

添加代码如下:

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
// 新增的postcss
import postcss from 'rollup-plugin-postcss';
export default {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 // 新增的postcss
 postcss({
 extensions: ['.css']
 }),
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 }),
 replace({
 ENV: JSON.stringify(process.env.NODE_ENV || 'development')
 }),
 (process.env.NODE_ENV === 'production' && uglify()),
 serve({
 open: true, // 是否打开浏览器
 contentBase: './', // 入口html的文件位置
 historyApiFallback: true, // Set to true to return index.html instead of 404
 host: 'localhost',
 port: 10002
 }),
 livereload()
 ]
}

运行npm run build 后,可以看到生成的 dist/js/main.min.js 中的代码,在文件开头几行,可以看到一个名叫__$styleInject()的新函数;

代码如下:

function __$styleInject(css, returnValue) {
 if (typeof document === 'undefined') {
 return returnValue;
 }
 css = css || '';
 var head = document.head || document.getElementsByTagName('head')[0];
 var style = document.createElement('style');
 style.type = 'text/css';
 head.appendChild(style);
 
 if (style.styleSheet){
 style.styleSheet.cssText = css;
 } else {
 style.appendChild(document.createTextNode(css));
 }
 return returnValue;
}

这个函数创建了一个<style>元素并设置样式,然后添加到文档的<head>标签中。

但现在这些样式并没有真正地被处理;PostCSS只是直接地传输了我们的样式。让我们添加一些需要的PostCSS插件,使得样式能在目标浏览器上工作。

3. 安装必要的 PostCSS插件

下面需要安装四个插件,如下插件:

postcss-simple-vars 可以使用Sass风格的变量(e.g. myColor: #fff;,color:myColor: #fff;,color:myColor;)而不是冗长的CSS语法(e.g. :root {--myColor: #fff},color: var(--myColor))。

postcss-nested 允许使用嵌套规则。实际上我不用它写嵌套规则;

postcss-cssnext 这个插件集使得大多数现代CSS语法(通过最新的CSS标准)可用,编译后甚至可以在不支持新特性的旧浏览器中工作。

cssnano — 压缩,减小输出CSS文件大小。相当于JavaScript中对应的UglifyJS。

使用如下命令安装即可:

npm install --save-dev postcss-simple-vars postcss-nested postcss-cssnext cssnano

我们再来更下 rollup.config.js

现在我们可以在rollup.config.js 中引入 postcss插件了,在配置对象的plugins属性上添加一个postcss。

如下代码:

// Rollup plugins
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import replace from 'rollup-plugin-replace';
import uglify from 'rollup-plugin-uglify';
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
// 新增 rollup-plugin-postcss 插件
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 {
 input: './src/main.js',
 output: {
 file: './dist/js/main.min.js',
 format: 'iife'
 },
 plugins: [
 // 新增的
 postcss({
 extensions: ['.css'],
 plugins: [
 simplevars(),
 nested(),
 cssnext({ warnForDuplicates: false, }),
 cssnano()
 ]
 }),
 resolve({
 jsnext: true, // 该属性是指定将Node包转换为ES2015模块
 // main 和 browser 属性将使插件决定将那些文件应用到bundle中
 main: true, // Default: true 
 browser: true // Default: false
 }),
 commonjs(),
 json(),
 babel({
 exclude: 'node_modules/**' // 排除node_modules 下的文件
 }),
 replace({
 ENV: JSON.stringify(process.env.NODE_ENV || 'development')
 }),
 (process.env.NODE_ENV === 'production' && uglify()),
 serve({
 open: true, // 是否打开浏览器
 contentBase: './', // 入口html的文件位置
 historyApiFallback: true, // Set to true to return index.html instead of 404
 host: 'localhost',
 port: 10002
 }),
 livereload()
 ]
}

现在我们再来运行 npm run build, 后再打开浏览器就可以看到了head里面新增样式了,并且已经压缩的。

注意:在cssnext()中配置了{ warnForDuplicates: false }是因为它和cssnano()都使用了Autoprefixer,会导致一个警告。 我们只需要知道它被执行了两次(在这个例子中没什么坏处)并且取消了警告。

同理我们运行命令 npm run watch 后,修改css,也能实时加载到最新的css了。

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: