module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory'],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}
]
}
‘babel-loader?cacheDirectory’
You can also speed up babel-loader by as much as 2x by using the cacheDirectory option. This will cache transformations to the filesystem.
[BABEL] Note: The code generator has deoptimised the styling of “/Users/xxx/Documents/xxx/webpack_test/test3/node_modules/lodash/lodash.js” as it exceeds the max of “500KB”.
加上exclude限定局限就不会报错了
resolve: {
modules: [path.resolve('node_modules'), path.resolve('lib')]
}
modules: [path.resolve(__dirname, "src"), "node_modules"]
Module not found: Error: Can’t resolve ‘ajax’ in ‘/Users/xxx/Documents/xxx/webpack_test/test3/src’
当你须要指定除node_modules以外的别的模块目次的时刻可以在数组中增加属性
装置的第三方模块中都邑有一个 package.json文件,用于形貌这个模块的属性,个中有些字段用于形貌进口文件在那里,resolve.mainFields 用于设置采纳哪一个字段作为进口文件的形貌。
可以存在多个字段形貌进口文件的缘由是由于有些模块可以同时用在多个环境中,针对差异的运转环境须要运用差异的代码。 以 isomorphic-fetch API 为例,它是 Promise的一个完成,但可同时用于浏览器和 Node.js 环境。
为了削减搜刮步骤,在你明白第三方模块的进口文件形貌字段时,你可以把它设置的只管少。 由于大多数第三方模块都采纳 main字段去形貌进口文件的位置,可以如许设置 Webpack:
module.exports = {
resolve: {
// 只采纳 main 字段作为进口文件形貌字段,以削减搜刮步骤
mainFields: ['main'],
},
};
alias: {
"bootstrap": "bootstrap/dist/css/bootstrap.css"
}
module: {
noParse: [/react\.min\.js/]
}
被疏忽掉的文件里不应该包括 import 、 require 、 define 等模块化语句
dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包括给其他模块挪用的函数和数据
定义插件(DLLPlugin) —> 援用插件(DllReferencePlugin)
本次例子用jquery举例
webpack.jquery.config.js
module.exports = {
entry: ["jquery"],
output: {
filename: "vendor.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: 'var',// 打包的体式格局,hou
library: "vendor_lib_vendor"// DLL的名字
},
plugins: [
new webpack.DllPlugin({
name: "vendor_lib_vendor",// 定义DLL
path: path.resolve(__dirname, "dist/vendor-manifest.json")
})
]
};
package.json 的scripts增加
"dll": "webpack --config webpack.jquery.config.js --mode development"
设置好上述的文件后,在终端运转 npm run dll
,时刻会在dist目次下天生两个文件,分别是vendor.js
和 vendor-manifest.json
。vendor.js
包括的就是打包后的jquery
文件代码,vendor-manifest.json
是用来做关联的。DLL定义好了,接下来就是运用打包好的DLL了。
webpack.config.js 设置文件中引入DllPlugin插件打包好的动态衔接库
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require("./dist/vendor-manifest.json")
})
],
app.html
在app.html的底部增加
libraryTarget
和
library
当用 Webpack 去构建一个可以被其他模块导入运用的库时须要用到它们。
output.libraryTarget 是字符串的罗列范例,支撑以下设置。
编写的库将经由过程 var 被赋值给经由过程 library 指定称号的变量。
假如设置了 output.library=’LibraryName’,则输出和运用的代码以下:
// Webpack 输出的代码
var LibraryName = lib_code; //个中 lib_code 代指点出库的代码内容,是有返回值的一个自实行函数。
// 运用库的要领
LibraryName.doSomething();
编写的库将经由过程 CommonJS 范例导出。
假如设置了 output.library=’LibraryName’,则输出和运用的代码以下:
// Webpack 输出的代码
exports['LibraryName'] = lib_code;
// 运用库的要领
require('library-name-in-npm')['LibraryName'].doSomething();
// 个中 library-name-in-npm 是指模块宣布到 Npm 代码堆栈时的称号。
编写的库将经由过程 CommonJS2 范例导出,输出和运用的代码以下:
// Webpack 输出的代码
module.exports = lib_code;
// 运用库的要领
require('library-name-in-npm').doSomething();
CommonJS2 和 CommonJS 范例很类似,差异在于 CommonJS 只能用 exports 导出,而 CommonJS2 在 CommonJS 的基础上增加了 module.exports 的导出体式格局。
在 output.libraryTarget 为 commonjs2 时,设置 output.library 将没有意义。
编写的库将经由过程 this 被赋值给经由过程 library 指定的称号,输出和运用的代码以下:
// Webpack 输出的代码
this['LibraryName'] = lib_code;
// 运用库的要领
this.LibraryName.doSomething();
编写的库将经由过程 window 被赋值给经由过程 library 指定的称号,即把库挂载到 window 上,输出和运用的代码以下:
// Webpack 输出的代码
window['LibraryName'] = lib_code;
// 运用库的要领
window.LibraryName.doSomething();
编写的库将经由过程 global 被赋值给经由过程 library 指定的称号,即把库挂载到 global 上,输出和运用的代码以下:
// Webpack 输出的代码
global['LibraryName'] = lib_code;
// 运用库的要领
global.LibraryName.doSomething();
HappyPack就能让Webpack把使命剖析给多个子历程去并发的实行,子历程处置惩罚完后再把效果发送给主历程。
install
由于webpack 4.0 方才宣布,相应的插件还没有更新完,不过可以在背面加一个@next
来装置行将宣布的版本
npm i happypack@next -D
webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: 'happypack/loader?id=css',
//把对.js文件的处置惩罚转交给id为babel的HappyPack实例
//用唯一的标识符id来代表当前的HappyPack是用来处置惩罚一类特定文件
include: path.resolve('./src'),
exclude: /node_modules/
},
{
test: /\.js/,
use: 'happypack/loader?id=babel',
include: path.resolve('./src'),
exclude: /node_modules/
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html'
}),
new HappyPack({
id: 'babel',
loaders: ['babel-loader']// 和rules里的设置雷同
}),
new HappyPack({
id: 'css',
loaders: ['style-loader', 'css-loader']// 和rules里的设置雷同
}),
]
insatll
npm install webpack-parallel-uglify-plugin -D
webpackage.config.js
new ParallelUglifyPlugin({
workerCount: os.cpus().length - 1,//开启几个子历程去并发的实行紧缩。默许是当前运转电脑的 CPU 核数减去1
uglifyJS: {
output: {
beautify: false, //不须要格式化
comments: true, //不保留解释
},
compress: {
warnings: false, // 在UglifyJs删除没有用到的代码时不输出正告
drop_console: true, // 删除一切的 `console` 语句,可以兼容ie浏览器
collapse_vars: true, // 内嵌定义了然则只用到一次的变量
reduce_vars: true, // 提取出涌现屡次然则没有定义成变量去援用的静态值
}
}
})
watch: true,
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 300,
poll: 1
}
watch
只要在开启监听形式时(watch为true),watchOptions才有意义
aggregateTimeout
监听到变化发生后等300(ms)再去实行行动,防备文件更新太快致使编译频次太高
poll
经由过程不断的讯问文件是不是改变来推断文件是不是发生变化,默许每秒讯问1000次
文件监听流程
webpack定时猎取文件的更新时候,并跟上次保留的时候举行比对,不一致就示意发生了变化,poll就用来设置每秒问多少次。
当检测文件不再发生变化,会先缓存起来,等守候一段时候后以后再关照监听者,这个守候时候经由过程aggregateTimeout设置。
webpack只会监听entry依靠的文件
我们须要只管削减须要监听的文件数目和搜检频次,固然频次的下落会致使灵敏度下落。
devServer: {
inline: true
},
webpack担任监听文件变化,webpack-dev-server担任革新浏览器。这些文件会被打包到chunk中,它们会代办客户端向服务器提议WebSocket衔接
webpack.config.js
devServer: {
hot:true//将hot设置为true
},
// 须要的插件
plugins: [
new webpack.NamedModulesPlugin(),//显现模块的相对途径
new webpack.HotModuleReplacementPlugin()// 启动热加载功用
]
code
if (module.hot) {
module.hot.accept('./hot.js', () => {
let hot = require('./hot');
document.getElementById('app2').innerHTML = hot + '1';
})
}
须要热加载的模块须要在初始化的时刻引入到模块中,不然不会触发HMR。
在开辟网页的时刻,平常都邑有多套运转环境,比方,在开辟过程当中轻易开辟调试的环境。宣布到线上给用户运用的运转环境。
线上的环境和开辟环境区分主要有以下差异:
package.json
cross-env
跨平台设置环境变量(背面没有&&)"scripts": {
"build-dev": "cross-env NODE_ENV=development webpack --mode development",
"build-prod": "cross-env NODE_ENV=production webpack --mode production"
}
webpack.config.js
webpack.base.config.js
兼并,临盆环境(或许开辟环境)的优先级高于webpack.base.config.js
的设置。let merge = require('webpack-merge');
let base = require('./webpack.base.config');
let other = null;
if (process.env.NODE_ENV === 'development') {
other = require('./webpack.dev.config');
} else {
other = require('./webapack.prod.config');
}
module.exports = merge(base, other);
webpack.base.config.js
webpack.DefinePlugin
定义环境变量基础设置...
plugins: [
new webpack.DefinePlugin({
__isDevelopment__: JSON.stringify(process.env.NODE_ENV == 'development')
})
]
webpack.dev.config.js
output
举例,假如开辟和临盆环境的参数差异,就会掩盖webpack.base.config.js
内里的设置const path = require('path');
module.exports = {
output: {
path: path.resolve('./dist'),
filename: "[name].dev.[hash:2].js"
}
};
webpack.prod.config.js
output
举例)const path = require('path');
module.exports = {
output: {
path: path.resolve('./dist'),
filename: "[name].prod.[hash:8].js"
}
};
base.js
webpack.DefinePlugin
定义的变量(__isDevelopment__
),在进口文件和进口文件援用的其他文件中都可以猎取到__isDevelopment__
的值let env = null;
if (__isDevelopment__) {
env = 'dev';
} else {
env = 'prod';
}
module.exports = env;
index.js
let env = require('./base.js');
if (__isDevelopment__) {
console.log('dev');
} else {
console.log('prod');
}
console.log('env', env);
/*
prod
env prod
*/
webpack.DefinePlugin
定义环境变量的值时用 JSON.stringify 包裹字符串的缘由是环境变量的值须如果一个由双引号包裹的字符串,而 JSON.stringify(‘production’)的值恰好即是'”production”‘
CDN 又叫内容分发收集,经由过程把资本布置到世界各地,用户在接见时根据就近准绳从离用户近来的服务器猎取资本,从而加快资本的猎取速率。
tree Shaking 可以用来剔除Javascript中用不上的死代码。
use: {
loader: 'babel-loader',
query: {
presets: [
[
"env", {
modules: false //寄义是封闭 Babel 的模块转换功用,保留底本的 ES6 模块化语法
}
],
"react"
]
}
},
须要注重的是它依靠静态的ES6模块化语法,比方经由过程import和export导入导出。也就是说假如项目代码运转在不支撑es6语法的环境上,Tree Shaking也就没有意义了。
大网站有多个页面,每一个页面由于采纳雷同手艺栈和款式代码,会包括许多大众代码,假如都包括进来会有题目
雷同的资本被反复的加载,糟蹋用户的流量和服务器的本钱;
每一个页面须要加载的资本太大,致使网页首屏加载迟缓,影响用户体验。 假如能把大众代码抽离成零丁文件举行加载能举行优化,可以削减收集传输流量,下落服务器本钱
差异范例的文件,打包后的代码块也差异:
webpack.config.js
optimization: {
splitChunks: {
cacheGroups: {
commons: {// 页面之间的公用代码
chunks: 'initial',
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
},
vendor: {// 基础类库
chunks: 'initial',
test: /node_modules/,
name: "vendor",
priority: 10,
enforce: true
}
}
}
},
./src/pageA.js
require('./utils/utility1.js');
require('./utils/utility2.js');
require('react');
./src/pageB.js
require('./utils/utility2.js');
require('./utils/utility3.js');
./src/pageC.js
require('./utils/utility2.js');
require('./utils/utility3.js');
utils/utility1.js
module.exports = 1;
utils/utility2.js
module.exports = 2;
utils/utility3.js
module.exports = 3;
打包后的效果
上述三种代码的天生的效果,以下图:
Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运转的更快, 它又译作 “作用域提拔”,是在 Webpack3 中新推出的功用。
package.json
"build": "webpack --display-optimization-bailout --mode development",
webpack.config.js
plugins: [
new ModuleConcatenationPlugin()
],
./h.js
export default 'scope hoist'
./index.js
import str from './h.js'
console.log(str);
必需运用ES6语法,不然不起作用(
--display-optimization-bailout
参数会提醒)
代码星散是 webpack 中最有目共睹的特征之一。此特征可以把代码星散到差异的 bundle 中,然后可以按需加载或并行加载这些文件。 有三种经常使用的代码星散要领:
进口出发点和防备反复上面已提到了,下面我们重点讲一下动态导入
用户当前须要用什么功用就只加载这个功用对应的代码,也就是所谓的按需加载 在给单页运用做按需加载优化时,平常采纳以下准绳:
import(module)
的语法document.getElementById('play').addEventListener('click',function(){
import('./vedio.js').then(function(video){
let name = video.getName();
console.log(name);
});
});