使用Prepack
认识 Prepack
为了优化代码在运行时的效率,由FaceBook开源,在运行结果一致的情况下,改变远吗的运行逻辑,输出性能更好的js代码,实际上,Prepack就是一个部分求值器,编译代码时提前将计算结果放到遍以后的代码中,而不是在代码运行时才去求值。 例如:
import React, {Component} from 'react';
import {renderToString} from 'react-dom/server';
function hello(name) {
return 'hello' + name;
}
class Button extends Component {
render() {
return hello(this.props.name);
}
}
console.log(renderToString(<Button name='webpack' />));
被Prepack转换后直接输出console.log("hello webpack"),Prepack通过在预先执行代码来得到执行结果,再直接将运行结果输出来提升性能。
工作原理及流程:
- 通过Babel将js代码解析成AST
- Prepack实现一个js解释器,用于执行代码,借助解释器,Prepack才能理解远吗具体如何执行,并将执行过程中的结果返回到输出中。 但是
- 不能识别DOM API和部分Node.js API,如果在代码中有调用依赖运行环境的API,会导致Prepack报错
- 代码在优化后性能可能更差
- 代码优化后,文件的尺寸可能大大增加 --------------------------------->所以现在将Prepack用于线上环境还过早
接入 Webpack
Prepack需要在Webpack输出最终代码之前,对这些代码进行优化,因此新引入一个插件:prepack-webpack-plugin
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default;
module.exports = {
plugins: [
new PrepackWebpackPlugin()
]
}
开启 Scope Hoisting
Scope Hoisting可以让webpack打包出来的代码文件更小,运行更快,又被译作--作用域提升--,webpack 3中新推出的功能。
认识Scope Hoisting
假设:两个文件:
uitl.js:export default 'Hello, Webpack';
main.js:
import str from './util.js';
console.log(str)
webpack打包后输出的部分代码:
[
(function (module, __webpack_exports__, __webpack_require__) {
var __WEBPACK_IMPORTED_MODULE_0__util_js__=__webpack_require__(1);
console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);
}),
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["a"] = ('Hello, Webpack');
})
]
开启Scope Hoisting后,同样的代码输出部分代码如下:
[
(function (module, __webpack_exports__, __webpack_require__) {
var util = ('Hello, Webpack');
console.log(util);
})
]
开启Scope Hoisting后,函数申明由两个变成一个, util.js中定义的内容被直接注入main.js对应的模块中,好处如下:
- 代码体积更小(因为函数申明语句会产生大量的代码)
- 代码在运行时因为创建的函数作用域变少了,所以内存开销也变小了
Scope Hoisting会分析模块之间的依赖关系,尽可能将被打散的模块合并到一个函数中,但前提是不能造成代码冗余。因此只有被引用了一次的模块才能被合并。 由于Scope Hoisting需要分析模块之间的依赖关系,因此代码必须采用es6模块化语句,不然会无法生效。
使用Scope Hoisting
Scope Hoisting是webpack内置的功能,只需要配置一个插件,相关代码如下:
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatentationPlugin');
module.exports = {
plugins: [
// 开启Scope Hoisting
new ModuleConcatenationPlugin(),
]
}
同时,考虑到Scope Hoisting依赖源码时需采用ES6模块化语法,还需要配置mainFields。大部分Npm中的第三方库采用了CommonJS语法,但部分库会同时提供ES6模块化的代码,所以为充分发挥Scope Hoisting的作用,增加以下配置:
module.exports = {
resolve: {
// 针对Npm中的第三方模块优先采用jsnext:main中指向的ES6模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
}
}
对于采用了非ES6模块化语法的代码,webpack会降级处理且不使用Scope Hoisting优化。 开启Scope Hoisting并发挥最大作用的配置如下:
const MOduleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 针对Npm中的第三方模块优先采用jsnext:main中指向的ES6模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启Scope Hoisting
new ModuleConcatenationPlugin(),
]
}