module:{
rules:[
{
test:/\.js$/,
use:['babel-loader?cacheDirectory'],
+ include:path.resolve(__dirname,'src'),
+ exclude:/node_modules/
}
]
}
复制代码
resolve: {
modules: [path.resolve(__dirname, 'node_modules')]
},
复制代码
mainFields
用于配置第三方模块使用那个入口文件 isomorphic-fetchcss
resolve.alias
配置项经过别名来把原导入路径映射成一个新的导入路径 此优化方法会影响使用Tree-Shaking
去除无效代码node
alias: {
'react': path.resolve(__dirname, './node_modules/react/cjs/eact.production.min.js')
}
复制代码
在导入语句没带文件后缀时,Webpack会自动带上后缀后去尝试询问文件是否存在 默认后缀是 extensions: ['.js', '.json']
react
resolve: {
+ extensions: ['js']
},
复制代码
module.noParse 配置项可让 Webpack 忽略对部分没采用模块化的文件的递归解析处理webpack
module: {
+ noParse: [/react\.min\.js/]
}
复制代码
被忽略掉的文件里不该该包含 import 、 require 、 define 等模块化语句git
.dll 为后缀的文件称为动态连接库,在一个动态连接库中能够包含给其余模块调用的函数和数据github
module.exports = {
entry: {
react: ['react'] //react模块打包到一个动态链接库
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].dll.js', //输出动态链接库的文件名称
library: '_dll_[name]' //全局变量名称
},
plugins: [
new webpack.DllPlugin({
name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
]
}
复制代码
webpack --config webpack.dll.config.js --mode production
复制代码
plugins: [
+ new webpack.DllReferencePlugin({
+ manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),
+ })
],
复制代码
webpack --config webpack.config.js --mode development
复制代码
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。 happypackweb
npm i happypack@next -D
复制代码
module: {
rules: [{
test: /\.js$/,
//把对.js文件的处理转交给id为babel的HappyPack实例
+ use: 'happypack/loader?id=babel',
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}, {
//把对.css文件的处理转交给id为css的HappyPack实例
test: /\.css$/,
+ use: 'happypack/loader?id=css',
include: path.resolve(__dirname, 'src')
}],
noParse: [/react\.min\.js/]
},
复制代码
plugins: [
//用惟一的标识符id来表明当前的HappyPack是用来处理一类特定文件
new HappyPack({
id: 'babel',
//如何处理.js文件,和rules里的配置相同
loaders: [{
loader: 'babel-loader',
query: {
presets: [
"env", "react"
]
}
}]
}),
new HappyPack({
id: 'css',
loaders: ['style-loader', 'css-loader'],
threads: 4, //表明开启几个子进程去处理这一类型的文件
verbose: true //是否容许输出日子
})
],
复制代码
ParallelUglifyPlugin
能够把对JS文件的串行压缩变为开启多个子进程并行执行express
npm i -D webpack-parallel-uglify-plugin
复制代码
new ParallelUglifyPlugin({
workerCount: 3, //开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1
uglifyJS: {
output: {
beautify: false, //不须要格式化
comments: false, //不保留注释
},
compress: {
warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
drop_console: true, // 删除全部的 `console` 语句,能够兼容ie浏览器
collapse_vars: true, // 内嵌定义了可是只用到一次的变量
reduce_vars: true, // 提取出出现屡次可是没有定义成变量去引用的静态值
}
},
})
复制代码
咱们能够监听到本地源码文件发生变化时,自动从新构建出可运行的代码后再刷新浏览器npm
+ watch: true, //只有在开启监听模式时,watchOptions才有意义
+ watchOptions: {
+ ignored: /node_modules/,
+ aggregateTimeout: 300, //监听到变化发生后等300ms再去执行动做,防止文件更新太快致使编译频率过高
+ poll: 1000 //经过不停的询问文件是否改变来判断文件是否发生变化,默认每秒询问1000次
+ }
复制代码
aggregateTimeout
配置devServer: {
contentBase: './dist',
+ inline: true
},
复制代码
webpack负责监听文件变化,webpack-dev-server负责刷新浏览器 这些文件会被打包到chunk中,它们会代理客户端向服务器发起WebSocket链接json
+ [19] (webpack)-dev-server/client/overlay.js 3.58 KiB {0} [built]
+ [21] (webpack)-dev-server/client/socket.js 1.05 KiB {0} [built]
+ [22] ./node_modules/loglevel/lib/loglevel.js 7.68 KiB {0} [built]
+ [24] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
+ [31] ./node_modules/url/url.js 22.8 KiB {0} [built]
+ [32] (webpack)-dev-server/client?http://localhost:8080 7.75 KiB {0} [built]
+ [33] multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js 40 bytes {0} [built]
复制代码
模块热替换(Hot Module Replacement)的技术可在不刷新整个网页的状况下只更新指定的模块 原理是当一个源码发生变化时,只从新编译发生变化的模块,再用新输出的模块替换掉浏览器中对应的老模块
devServer: {
+ hot:true
}
复制代码
[./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built]
[0] multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/index.js 52 bytes {main} [built]
[./node_modules/webpack/hot/dev-server.js] (webpack)/hot/dev-server.js 1.66 KiB {main} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 77 bytes {main} [built]
复制代码
if (module.hot) {
module.hot.accept('./index.js', function () {
console.log('accept index.js');
});
}
复制代码
优化模块热替换浏览器日志
plugins: [
+ new webpack.NamedModulesPlugin(),
+ new webpack.HotModuleReplacementPlugin(),
]
复制代码
在开发网页的时候,通常都会有多套运行环境,例如:
if(process.env.NODE_ENV == 'production'){
console.log('生产环境');
}else{
console.log('开发环境');
}
复制代码
当你使用process模块的时候,webpack会把process模块打包进来
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV:JSON.stringify('production')
+ }
+ }),
复制代码
定义环境变量的值时用 JSON.stringify 包裹字符串的缘由是环境变量的值须要是一个由双引号包裹的字符串,而 JSON.stringify('production')的值正好等于'"production"'
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
})
复制代码
CDN 又叫内容分发网络,经过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
output: {
path: path.resolve(__dirname, 'dist'),
+ filename: '[name]_[hash:8].js',
+ publicPath: 'http://img.zhufengpeixun.cn'
},
复制代码
Tree Shaking
能够用来剔除JavaScript
中用不上的死代码。它依赖静态的ES6
模块化语法,例如经过import
和export
导入导出。
使用Tree
{
loader: 'babel-loader',
query: {
presets: [
[
+ "env", {
+ modules: false //含义是关闭 Babel 的模块转换功能,保留本来的 ES6 模块化语法
+ }
],
"react"
]
}
}
复制代码
webpack --display-used-exports
复制代码
+ const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
plugins: [
+ new UglifyJSPlugin()
]
复制代码
webpack --display-used-exports --optimize-minimize
webpack --mode production
复制代码
大网站有多个页面,每一个页面因为采用相同技术栈和样式代码,会包含不少公共代码,若是都包含进来会有问题
如何使用 common-chunk-and-vendor-chunk
entry: {
pageA: './src/pageA',
pageB: './src/pageB'
},
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: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
}
}
},
复制代码
Scope Hoisting 可让 Webpack 打包出来的代码文件更小、运行的更快, 它又译做 "做用域提高",是在 Webpack3 中新推出的功能。
export default 'Hello';
复制代码
import str from './hello.js';
console.log(str);
复制代码
var util = ('Hello');
console.log(util);
复制代码
函数由两个变成了一个,hello.js 中定义的内容被直接注入到了 main.js 中
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
复制代码
--display-optimization-bailout
复制代码
代码分离是 webpack 中最引人注目的特性之一。此特性可以把代码分离到不一样的 bundle 中,而后能够按需加载或并行加载这些文件。 有三种经常使用的代码分离方法:
`entry: {
index: './src/index.js',
another: './src/another-module.js'
}
复制代码
splitChunks能够将公共的依赖模块提提取到一个新生成的 chunk. common-chunk-and-vendor-chunk
optimization: {
splitChunks: {
cacheGroups: {
commons: {
chunks: "initial",
minChunks: 2
},
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
}
}
复制代码
用户当前须要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载 在给单页应用作按需加载优化时,通常采用如下原则:
document
.getElementById('clickMe')
.addEventListener('click', () => {
import (/*webpackChunkName:"alert"*/
'./alert').then(alert => {
console.log(alert);
alert.default('hello');
});
});
复制代码
loaders: [
{
loader: 'babel-loader',
query: {
presets: ["env", "stage-0", "react"]
}
}
]
复制代码
webpack-dev-middleware 插件对更改的文件进行监控,编译,通常和 webpack-hot-middleware 配合使用,实现热加载功能 webpack-dev-middleware webpack-hot-middleware
const path = require("path")
const express = require("express")
const webpack = require("webpack")
const webpackDevMiddleware = require("webpack-dev-middleware")
const webpackConfig = require('./webpack.config.js')
const app = express(),
DIST_DIR = path.join(__dirname, "dist"),// 设置静态访问文件路径
PORT = 9090, // 设置启动端口
complier = webpack(webpackConfig)
app.use(webpackDevMiddleware(complier, {
//绑定中间件的公共路径,与webpack配置的路径相同
publicPath: webpackConfig.output.publicPath,
quiet: true //向控制台显示内容
}))
// 这个方法和下边注释的方法做用同样,就是设置访问静态文件的路径
app.use(express.static(DIST_DIR))
app.listen(PORT,function(){
console.log("成功启动:localhost:"+ PORT)
})
复制代码
webpack --profile --json > stats.json
复制代码
Webpack 官方提供了一个可视化分析工具 Webpack Analyse
当用 Webpack 去构建一个能够被其余模块导入使用的库时须要用到它们。
output.libraryTarget 是字符串的枚举类型,支持如下配置。
编写的库将经过 var 被赋值给经过 library 指定名称的变量。
假如配置了 output.library='LibraryName',则输出和使用的代码以下:
// Webpack 输出的代码
var LibraryName = lib_code;
// 使用库的方法
LibraryName.doSomething();
假如 output.library 为空,则将直接输出:
复制代码
lib_code 其中 lib_code 代指导出库的代码内容,是有返回值的一个自执行函数。
编写的库将经过 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();复制代码