从 webpack v1 迁徙到 webpack v2 新特征
迎接小伙伴们为 前端导航平台 点star
github堆栈: https://github.com/pfan123/fr…
接见 前端导航平台
Tree Shaking
Tree shaking 是一个术语,一般用来形貌移除 JavaScript 高低文中无用代码这个历程,或许更准确的说是按需援用代码,它依靠于 ES2015 模块体系中 import/export
的静态构造特征。这个术语和观点现实上是鼓起于 ES2015 模块打包东西 rollup。
webpack 2 原生支撑ES6模块 (别号 harmony modules) ,并能检测出未运用的模块输出。
示例:举一个 maths.js 库例子,它输出两个要领 square 和 cube:
// 这个函数没有被其他处所援用过
export function square(x) {
return x * x;
}
// 这个函数被援用了
export function cube(x) {
return x * x * x;
}
在 main.js 中我们只援用 cube
要领:
import {cube} from './maths.js';
console.log(cube(5)); // 125
运转 node_modules/.bin/webpack main.js dist.js 并搜检 dist.js 可发明 square 没有被输出:
/* ... webpackBootstrap ... */
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* unused harmony export square */
/* harmony export (immutable) */ __webpack_exports__["a"] = cube;
// 这个函数没有被其他处所援用过
function square(x) {
return x * x;
}
// 这个函数被援用了
function cube(x) {
return x * x * x;
}
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__maths_js__ = __webpack_require__(0);
console.log(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__maths_js__["a" /* cube */])(5)); // 125
/***/ })
resolve.root
, resolve.fallback
, resolve.modulesDirectories
上述三个选项将被合并为一个范例设置项:resolve.modules. 更多关于resolve的信息信息可查阅 resolving.
resolve: {
- root: path.join(__dirname, "src")
+ modules: [
+ path.join(__dirname, "src"),
+ "node_modules"
+ ]
}
resolve.extensions
该设置项将不再要求强迫转入一个空字符串,而被修正到了resolve.enforceExtension下, 更多关于resolve的信息信息可查阅 resolving.
resolve.*
更多相干修正和一些不经常使用的设置项在此不一一列举,人人假如在现实项目中用到可以到resolving)中举行检察.
module.loaders
将变成 module.rules
旧版本中loaders设置项将被功用越发壮大的rules庖代,同时斟酌到新旧版本的兼容,之前旧版本的module.loaders
的相干写法照旧有效,loaders中的相干设置项也照旧可以被辨认。
新的loader设置规则会变得越发浅显易用,因而官方也异常引荐用户能实时按module.rules
中的相干设置举行调解晋级。
module: {
- loaders: [
+ rules: [
{
test: /\.css$/,
- loaders: [
+ use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
- query: {
+ options: {
modules: true
}
}
]
},
{
test: /\.jsx$/,
loader: "babel-loader", // Do not use "use" here
options: {
// ...
}
}
]
}
链式loaders
同webpack1.X中相似,loaders继承支撑链式写法,可将相干正则婚配到的文件资本数据在几个loader之间举行同享通报,细致运用说明可见 rule.use。
在wepback2中,用户可经由过程use
项来指定须要用到的loaders列表(官方引荐),而在weback1中,假如须要设置多个loaders则须要依托简朴的 !
符来切分,这类语法出于新旧兼容的斟酌,只会在module.loaders
中见效。
module: {
- loaders: {
+ rules: {
test: /\.less$/,
- loader: "style-loader!css-loader!less-loader"
+ use: [
+ "style-loader",
+ "css-loader",
+ "less-loader"
+ ]
}
}
module
称号后自动自动补全 -loader
的功用将被移除
在设置loader时,官方不再许可省略-loader
扩展名,loader的设置写法大将逐渐趋于严谨。
module: {
rules: [
{
use: [
- "style",
+ "style-loader",
- "css",
+ "css-loader",
- "less",
+ "less-loader",
]
}
]
}
固然,假如你想继承坚持之前的省略写法,你写可以在resolveLoader.moduleExtensions
中开启默许扩展名设置,不过这类做法并不被引荐。
+ resolveLoader: {
+ moduleExtensions: ["-loader"]
+ }
可以从这里检察 #2986此次变动的缘由;
json-loader
无须要自力装置
当我们须要读取json花样文件时,我们不再须要装置任何loader,webpack2中将会内置 json-loader,自动支撑json花样的读取(喜大普奔啊)。
module: {
rules: [
- {
- test: /\.json/,
- loader: "json-loader"
- }
]
}
为什么须要默许支撑json花样官方的诠释是为了在webpack, node.js and browserify三种构建环境下供应无差别的开辟体验。
loader
设置项将默许从context
中读取
在webpack 1中的一些特别的loader在读取对应资本时,须要经由过程require.resolve
指定后才指定见效。从webpack 2后,设置loader在直接从context
中举行读取,这就处置惩罚了一些在运用“npm链接”或援用模块以外的context
形成的模块反复导入的题目。
设置中可以删除以下代码:
module: {
rules: [
{
// ...
- loader: require.resolve("my-loader")
+ loader: "my-loader"
}
]
},
resolveLoader: {
- root: path.resolve(__dirname, "node_modules")
}
module.preLoaders
和 module.postLoaders
将被移除
module: {
- preLoaders: [
+ rules: [
{
test: /\.js$/,
+ enforce: "pre",
loader: "eslint-loader"
}
]
}
之前须要用到preLoader的处所可以改到rules的enfore中举行设置。
UglifyJsPlugin
中的 sourceMap
设置项将默许封闭
UglifyJsPlugin
中的sourceMap
默许项将从 true
变成 false
。
这就意味着当你的js编译紧缩后,须要继承读取原始剧本信息的行数,位置,正告等有效调试信息时,你须要手动开启UglifyJsPlugin
的设置项:sourceMap: true
。
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ sourceMap: true
})
]
UglifyJsPlugin
的正告设置将默许封闭
UglifyJsPlugin
中的 compress.warnings
默许项将从 true
变成 false
。
这就意味着当你想在编译紧缩的时刻检察一部份js的正告信息时,你须要将compress.warnings
手动设置为 true
。
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ compress: {
+ warnings: true
+ }
})
]
UglifyJsPlugin
不再支撑让 Loaders
最小化文件的情势了
UglifyJsPlugin
将不再支撑让 Loaders 最小化文件的情势。debug
选项已被移除。Loaders 不能从 webpack 的设置中读取到他们的设置项。
loade的最小化文件情势将会在webpack 3或许后续版本中被完全取消掉.
为了兼容部份旧式loader,你可以经由过程 LoaderOptionsPlugin
的设置项来供应这些功用。
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ minimize: true
+ })
]
DedupePlugin
已被移除
webpack.optimize.DedupePlugin
不再须要. 从你之前的设置移除这个设置选项.
BannerPlugin
设置项将有所转变
BannerPlugin
将不再许可接收两个参数,而是只供应一个对象设置项.
plugins: [
- new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+ new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
]
OccurrenceOrderPlugin
将被内置到场
不须要再针对OccurrenceOrderPlugin
举行设置
plugins: [
- new webpack.optimize.OccurrenceOrderPlugin()
]
ExtractTextWebpackPlugin
设置项将有所转变
ExtractTextPlugin ] 1.0.0 在webpack v2将没法运用,你须要从新指定装置ExtractTextPlugin
的webpack2的适配版本.
npm install --save-dev extract-text-webpack-plugin@beta
更新后的ExtractTextPlugin
版本会针对wepback2举行响应的调解。
ExtractTextPlugin.extract
的设置誊写体式格局将调解
module: {
rules: [
test: /.css$/,
- loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" })
+ loader: ExtractTextPlugin.extract({
+ fallbackLoader: "style-loader",
+ loader: "css-loader",
+ publicPath: "/dist"
+ })
]
}
new ExtractTextPlugin({options})
的设置誊写体式格局将调解
plugins: [
- new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
+ new ExtractTextPlugin({
+ filename: "bundle.css",
+ disable: false,
+ allChunks: true
+ })
]
全量动态加载资本将默许失效
只要运用一个表达式的资本依靠援用(i. e. require(expr)
),如今将建立一个空的context,而不是一个context的完全目次。
当在es2015的模块化中没法事情时,请最好重构这部份的代码,假如没法举行修正这部份代码,你可以在ContextReplacementPlugin
中来提醒编译器做出准确处置惩罚。
Cli运用自定义参数作为设置项传入体式格局将做调解
假如你随便将自定义参数经由过程cli传入到设置项中,如:
webpack --custom-stuff
// webpack.config.js
var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
/* ... */
module.exports = config;
你会发明这将不会被许可,cli的实行将会遵照越发严厉的范例。
取而代之的是用一个接口来做通报参数设置。这应当是新的替代计划,将来的东西开辟也可以依靠于此。
webpack --env.customStuff
module.exports = function(env) {
var customStuff = env.customStuff;
/* ... */
return config;
};
检察更多引见 CLI.
require.ensure
和 AMD require
将采纳异步式挪用
require.ensure
和amd require
将默许采纳异步的加载体式格局来挪用,而非之前确当模块要求加载完成后再在回调函数中同步触发。
require.ensure
将基于原生的Promise
对象从新完成,当你在运用 require.ensure
时请确保你的运转环境默许支撑Promise对象,假如缺少则引荐运用装置polyfill.
Loader的设置项将经由过程options
来设置
在webpack.config.js
中将不再许可运用自定义属性来设置loder,这直接带来的一个影响是:在ts
设置项中的自定义属性将没法在被在webpack2中准确运用:
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader'
}]
},
// does not work with webpack 2
ts: { transpileOnly: false }
}
什么是 options
?
这是一个异常好的发问,严厉意义上来讲,custom property
和options
均是用于webpack loader的设置体式格局,从更浅显的说法上看,options
应当被称作query
,作为一种相似字符串的情势被追加到每一个loader的定名背面,异常相似我们用于url中的查询字符串,但在现实运用中功用要越发壮大:
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false })
}]
}
}
options也可作为一个自力的字面对象量,在loader的设置中搭配运用。
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader',
options: { transpileOnly: false }
}]
}
}
LoaderOptionsPlugin
context
部份loader须要设置context
信息, 而且支撑从设置文件中读取。这须要loader经由过程用长选项通报进来,更多loader
的明细设置项可以查阅相干文档。
为了兼容部份旧式的loader设置,也可以采纳以下插件的情势来举行设置:
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ options: {
+ context: __dirname
+ }
+ })
]
debug
debug
作为loader中的一个调试情势选项,可以在webpack1的设置中天真切换。在webpack2中,则须要loader
经由过程用长选项通报进来,更多loader的明细设置项可以查阅相干文档。
loder的debug
情势在webpack3.0或许后续版本中将会被移除。
为了兼容部份旧式的loader设置,也可以采纳以下插件的情势来举行设置:
- debug: true,
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ debug: true
+ })
]
Code Splitting with ES2015
在webpack1中,你须要运用require.ensure
完成chunks
的懒加载,如:
require.ensure([], function(require) {
var foo = require("./module");
});
在es2015的 loader中经由过程定义import()
作为资本加载要领,当读取到相符ES2015范例的模块时,可完成模块中的内容在运转时动态加载。
webpack在处置惩罚import()
时可以完成按需提取开辟中所用到的模块资本,再写入到各个自力的chunk中。webpack2已支撑原生的 ES6 的模块加载器了,这意味着 webpack 2 可以明白和处置惩罚 import
和export
了。
import()
支撑将模块名作为参数相差而且返回一个Promise
对象。
function onClick() {
import("./module").then(module => {
return module.default;
}).catch(err => {
console.log("Chunk loading failed");
});
}
如许做的另有一个分外的优点就是当我们的模块加载失利时也可以被捕捉到了,由于这些都邑遵照Promise
的范例来完成。
值得注意的处所:require.ensure
的第三个参数选项许可运用简朴的chunk定名体式格局,然则import
API中将不被支撑,假如你愿望继承采纳函数式的写法,你可以继承运用require.ensure
。
require.ensure([], function(require) {
var foo = require("./module");
}, "custom-chunk-name");
(注: System.import
将会被弃用,webpack中将不再引荐运用 System.import
,官方也引荐运用import
举行替代,详见 v2.1.0-beta.28)
假如想要继承运用Babel中供应的import
,你须要自力装置 dynamic-import 插件而且挑选babel的Stage 3
来捕捉时的毛病, 固然这也可以依据现实情况来操纵而不做强迫束缚。
Dynamic expressions动态表达式
如今import()
中的传参可支撑部份表达式的写法了,假如之前有打仗过CommonJS中require()
表达式写法,应当不会对此觉得生疏,(它的操纵实在和 CommonJS 是相似的,给一切可以的文件建立一个环境,当你通报那部份代码的模块还不肯定的时刻,webpack 会自动天生一切可以的模块,然后依据需求加载。这个特征在前端路由的时刻很有效,可以完成按需加载资本)
import()
会针对每一个读取到的module建立自力的separte chunk
。
function route(path, query) {
return import(`./routes/${path}/route`)
.then(route => new route.Route(query));
}
// This creates a separate chunk for each possible route
可以混用 ES2015 和 AMD 和 CommonJS
在 AMD 和 CommonJS 模块加载器中,你可以夹杂运用一切(三种)的模块范例(即使是在同一个文件内里)。
// CommonJS consuming ES2015 Module
var book = require("./book");
book.currentPage;
book.readPage();
book.default === "This is a book";
// ES2015 Module consuming CommonJS
import fs from "fs"; // module.exports map to default
import { readFileSync } from "fs"; // named exports are read from returned object+
typeof fs.readFileSync === "function";
typeof readFileSync === "function";
注:es2015 balel
的默许预处置惩罚会把 ES6 模块加载器转化成 CommonJS 模块加载。如果想运用 webpack 新增的对原生 ES6 模块加载器的支撑,你须要运用 es2015-webpack
来替代,别的假如你愿望继承运用babel,则须要经由过程设置babel项,使其不会强迫剖析这部份的module symbols以便webpack能准确运用它们,babel的设置以下:
.babelrc
{
"presets": [
["es2015", { "modules": false }]
]
}
Hints
No need to change something, but opportunities
Template strings模板字符串
webpack中的资本参数已最先支撑模板字符串了,这意味着你可以运用以下的设置写法:
- require("./templates/" + name);
+ require(`./templates/${name}`);
设置支撑项支撑Promise
webpack如今在设置文件项中返回Promise
了,这就许可你在设置中可以举行一些异步的写法了,以下所示:
webpack.config.js
module.exports = function() {
return fetchLangs().then(lang => ({
entry: "...",
// ...
plugins: [
new DefinePlugin({ LANGUAGE: lang })
]
}));
};
Loader婚配支撑更多的高等写法
webpack中的loader设置支撑以下写法:
module: {
rules: [
{
resource: /filename/, // matches "/path/filename.js"
resourceQuery: /querystring/, // matches "/filename.js?querystring"
issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
}
]
}
更多的CLI参数项
以下有更多的CLI 参数项可用:
--define process.env.NODE_ENV="production"
支撑直接设置DefinePlugin
.
--display-depth
能显现每一个entry中的module的资本深度
--display-used-exports
能显现每一个module中依靠运用了哪些资本.
--display-max-modules
能限定显现output中援用到的资本数目 (默许显现15个).
-p 指定当前的编译环境为临盆环境,即修正:process.env.NODE_ENV
为 "production"
Cacheable缓存项
Loaders 如今默许可被缓存。Loaders 假如不想被缓存,须要挑选不被缓存。
// Cacheable loader
module.exports = function(source) {
- this.cacheable();
return source;
}
// Not cacheable loader
module.exports = function(source) {
+ this.cacheable(false);
return source;
}
Complex options复合参数项写法
webpack v1 只支撑可以「可 JSON.stringify的对象」作为 loader 的 options。
webpack2中的loader参数项中已可以支撑恣意的JS对象的写法了。
运用复合选项时会有一个限定,你须要设置一个ident
作为项来保证能准确援用到其他的loader,这意味着经由过程设置我们可以在内联写法中去挪用对应依靠的加载器,以下:
require("some-loader??by-ident!resource")
{
test: /.../,
loader: "...",
options: {
ident: "by-ident",
magic: () => return Math.random()
}
}
v2.2.1之前(即从 v2.0.0 到 v2.2.0),运用 Complex options,须要在 options 对象上增加 ident,许可它可以被其他 loader 援用。这在 v2.2.1 中被删除,因而现在的迁徙不再须要运用 ident 键。
{
test: /\.ext/
use: {
loader: '...',
options: {
- ident: 'id',
fn: () => require('./foo.js')
}
}
}