# webpack常用配置
# 1.安装核心模块
- webpack
- webpack-cli
** 注意: 因为在webpack 3中,webpack本身和它的CLI以前都是在同一个包中,但在第4版中,他们已经将两者分开来更好地管理它们。
为了方便,在package.json增加
"scripts": {
"webpack01": "webpack"
}
目录建立关系
执行npm run webpack01 即可进行打包。
由于没有配置文件,他会走自己的默认选项,且模式是mode:production ** 解释: 如果执行 npm run webpack01 ,会在找当前文件夹下的寻找webpack.config.js。如果找到会执行这个文件中的配置。如果没有找到也不会报错。会执行本身的0配置。 当然我们很少使用这样的配置文件。因此我们一般会自定义配置文件。 目录路径: webpack/01/webpack.base.js
const path = require('path');
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve('build')
}
}
# 2.entry
基本的使用方法是:
module.exports = {
entry:'./src/index.js',
// 或者
entry:['index.js','main.js'],
// 或者
entry:{
"index.js":"index.js",
"main.js":"main.js"
}
// 或者
entry:{
"index.js":["index.js","main.js"],
"main.js":["main.js","index.js"]
},
// 或者
entry:{
"index.js":["index.js","main.js"],
"main.js":["main.js","index.js"]
},
// 或者(这种不常用)
entry: () => './demo'
}
# 3.output
output里面的参数比较多,这里值介绍一个主要的参数;
module.exports = {
output:{
filename:'[id].[name].[hash:8].js',// hash,chunkhash,contenthash,
library: 'MyLibrary',// 定于 打包出来变量的名称
// 暴露为一个变量(一般不使用这种方式)
libraryTarget: "var"// var,this,window,global,commonjs,assign,
//模块定义系统
libraryTarget: "commonjs2"// commonjs2,amd,umd
path: path.resolve('build'),
publicPath: 'https://cdn.example.com/assets/'
}
}
注意: 详细的 请看webpack output (opens new window)
# 4.webpack-dev-server
文档链接:中文 (opens new window) , 英文 (opens new window)
常用方式
devServer: {
contentBase: "./build/", //监听代码变化自动提交并刷新网页
host: '0.0.0.0',
port: 8080,
proxy: { //配置代理
'/web/webApi': {
target: 'http://t1.zhuhuiyao.cn',
secure: false,
changeOrigin: true
}
}
}
// 使用node启动
var compiler = webpack(config);
const server = new WebpackDevServer(
compiler,
{
contentBase: path.join(__dirname, '../'),
quiet: true,
publicPath: '/dist/', //publicPath必填 否则就不好使
hot: true,
compress: true,
historyApiFallback: true,
}
)
server.listen(8080)
# webpack-dev-server提供了两种自动刷新模式:iframe和inline
# iframe
# 特点
在网页中嵌入了一个
iframe
,将我们自己的应用注入到这个iframe
当中去。在页面头部有一个提示框,用于显示构建过程的状态信息。
加载了
live.bundle.js
文件,其不但创建了iframe
标签,同时包含socket.io
的client
代码,以和webpack-dev-server
进行websocket
通讯,从而完成自动编译打包、页面自动刷新的功能。Iframe mode
下,浏览器访问的路径是:
localhost:8080/webpack-dev-server/index.html。
这个时候这个页面的header部分会出现整个reload
消息的状态。当源文件改变的时候,即可以完成自动编译打包、页面自动刷新的功能。
#
# 原理
当使用Iframe mode
时,请求/webpack-dev-server/index.html
路径时,会返回client/index.html
文件,这个文件的内容就是:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>
<script type="text/javascript" charset="utf-8" src="/__webpack_dev_server__/live.bundle.js"></script>
</head>
<body></body>
</html>
可看出,这个页面会请求live.bundle.js
文件,该文件里面会新建一个Iframe
,你的应用就被注入到了这个Iframe
当中。
同时live.bundle.js
中含有socket.io
的client
代码,这样它就能和webpack-dev-server
建立的http server
进行websocket
通讯了。并根据返回的信息完成相应的动作。
# inline
# 特点
- 构建消息在浏览器控制台显示。
socket.io
的client
代码被打包进了你的包(bundle
)中,以此来与webpack-dev-server
进行websocket
通讯,从而完成自动编译打包、页面自动刷新的功能。- 但是,每一个入口文件都会被插入上述的一段脚本,使得打包后的
bundle
文件很臃肿。
使用inline mode
的时候,这个时候访问的路径是:
localhost:8080/index.html
Inline mode
也能完成自动编译打包、页面自动刷新的功能,但是页面没有header部分的reload
消息的显示,不过在控制台中会显示reload
的状态。
# 原理
Inline-mode
,是webpack-dev-server
会在你的webpack.config.js
的入口配置文件中再添加一个入口,
module.exports = {
entry: {
app: [
'webpack-dev-server/client?http://localhost:8080/',
'./src/js/index.js'
]
},
output: {
path: './dist/js',
filename: 'bundle.js'
}
}
这样就完成了将inlined.js
打包进bundle.js
里的功能,同时inlined.js
里面也包含了socket.io
的client
代码,可以和webpack-dev-server
进行websocket
通讯。
当然你也可以直接在你index.html引入这部分代码:
<script src="http://localhost:8080/webpack-dev-server.js"></script>
# 总结
Iframe mode
和Inline mode
最后达到的效果都是一样的,都是监听文件的变化,然后再将编译后的文件推送到前端,完成页面的reload
的。- 通过设置
devServer.inline
切换两种模式,默认为inline
模式。 - 当使用HMR功能时,推荐使用
inline mode
。
# 5.loader
# 5.1 loader的特点
loader的特点,指责单一 使用多个loader需要用数组的形式 loader的执行顺序 默认是从右到左,从下到上。 loader 可以写成对象的形式
# 5.2 css 常用的cssloader
style-loader 把css 加入到 html中 css-loader // @import 解析路径 less-loader // 把less -> css postcss-loader// 添加兼容性 mini-css-extract-plugin // 将css 单独提出到一个文件中 optimize-css-assets-webpack-plugin // 装css进行压缩
# 5.3 babel-loader
常见配置方法。 官网链接 (opens new window)
rules: [
// the 'transform-runtime' plugin tells babel to require the runtime
// instead of inlining it.
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/transform-runtime']
}
}
}
]
想解决兼容性,及其减少依赖包的体积,请看下面这篇文件。 babel-polyfill VS babel-runtime VS babel-preset-env (opens new window)
# 5.4 eslint-loader
网站链接: eslint 中文 (opens new window) eslint 英文 (opens new window) 可以自定义配置规则。
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
// eslint options (if necessary)
}
}
# 6. html-webpack-plugin
常用用法:
{
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(), // Generates default index.html
new HtmlWebpackPlugin({ // Also generate a test.html
filename: 'test.html',
template: 'src/assets/test.html',
chunks: ['entry']
})
]
}
具体参考github仓库 (opens new window)
# 7. 引入全局模块
# 减少依赖包体积。
1.expose-loader 过于简单,不讲
2.webpack.ProvidePlugin
new webpack.ProvidePlugin({
Vue: ['vue/dist/vue.esm.js', 'default']
})
externals: {
jquery: 'jQuery'
}
8.sourceMap
# 8.watch 和 watchOptions 实现实时打包
watch: false,
watchOptions: {
aggregateTimeout: 300,
poll: 1000
}
# 9.常用小插件及其优化策略
1.copy-webpack-plugin 2.clean-webpack-plugin 3.webpack-merge 4.webpack.BannerPlugin 5.webpack.DefinePlugin 6.webpack.IgnorePlugin 7.DllPlugin DllReferencePlugin提高构建速度 (opens new window) 8.happypack
const webpack = require('webpack');
new webpack.BannerPlugin(banner);
new webpack.DefinePlugin({
// Definitions...
});
const HappyPack = require('happypack');
exports.module = {
rules: [
{
test: /.js$/,
// 1) replace your original list of loaders with "happypack/loader":
// loaders: [ 'babel-loader?presets[]=es2015' ],
use: 'happypack/loader',
include: [ /* ... */ ],
exclude: [ /* ... */ ]
}
]
};
exports.plugins = [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ]
})
];
# webpack 自带优化
tree-shaking原理 (opens new window)
# noParse
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import
, require
, define
的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
module: {
noParse: /jquery|lodash/,
}
# 懒加载
function sayHello() {
import('./non-esm.js').then(module => {
module.default.sayHello();
});
}
# 热更新,热加载
# 10.resolve
resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
},
extensions: ['.wasm', '.mjs', '.js', '.json']
}
# 11.optimization
optimization: {
minimize: false,
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
sourceMap: true, // Must be set to true if using source-maps in production
terserOptions: {
// https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
}
}),
],
splitChunks:{},
}