webpack 是一个现代 JavaScript 应用程序的静态模块打包器(static module bundler),简单来讲,是一个前端模块化打包编译工具,基本的功能包括代码转换,文件优化,代码分割,自动刷新等。
复制代码
webpack配置文件是基于node.js,而且遵循common.js来开发,
一般咱们会在根目录下新建一个webpack.config.js文件,基本的结构目录以下图所示:
复制代码
初始化:webpack3中,webpack和cli是在同一个包中,webpack4中已经分开。 yarn add webpack webpack-clicss
entry: {
main: './src/index.js' //单入口
}
复制代码
entry: {
main: './src/index.js', //多入口
test: './src/test.js'
}, //提示webpack把哪一个文件做为构建文件的入口
output: {
path: path.resolve(__dirname,'dist'),//必须是绝对路径
//filename: 'bundle.js'
filename:'[name].[hash:8].js'//打包多个文件,各自名字,而且加上md5戳,8位
}, //构建结束输出的位置
复制代码
打包后的js文件,名字bundle.js,若是想运行这个js,可是不能每次打包后都本身手动添加一个html,所以须要一个自动打包html的插件,而且可以自动把打包后的js添加上去。 第一个webpack插件 html-webpack-plugin 打包html做用 单入口html
let HtmlWebpackPlugin = rquire('html-webpack-plugin') //类
plugins: [
new HtmlWebpackPlugin({
fileName: 'index.html',//默认就是index.html
template: './public/index.html',
//以public下的index.html为模板打包
minify: {
removeAttributeQuotes: true, //去除引号
removeEmptyAttributes: true //清除全部的空属性
...
},
hash: true, //html引js避免缓存
...
})
]
复制代码
多入口自动打包引入js,利用循环前端
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
minify: {
removeAttributeQuotes: true,
removeEmptyAttributes: true
},
chunks: ['main'],//指定入口文件名字,自动引入相应js文件
hash: true
}),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'test.html',
chunks: ['test'],
hash: true
})
]
复制代码
每次更改完代码,不能每次都手动打包,所以须要创建本地开发服务器,插件webpack-dev-server,而且它是在内存中打包,并不会看到dist目录,和build不一样;而且修改代码会实时刷新。java
devServer: {//开发服务器配置,这里单独列出,不在plugins内
before(app){//若是不用转发,dev-server开启以前,前端本身mock数据
app.get('/api/user',function(req,res){
res.json({name:"fight"})
})
},
contentBase: path.join(__dirname, 'dist'),//来自dist目录的文件提供服务,默认是output输出位置
port: '3000',//更改端口号
progress: true,//打包时候进度条
compress:true //启动gzip压缩
<!--proxy: {//node代理,假如页面访问api,node自动转发到3000端口-->
<!-- '/api':{-->
<!-- target: 'http://localhost:3000',--> <!-- pathRewrite: {--> <!-- '/api': ''//假如路径中有/api,重写置空--> <!-- } --> <!-- }--> <!--}--> }, 复制代码
loader有三种写法,字符串,数组和对象 当js须要样式的时候,import并不能解析,所以须要loader来转换模块node
module: {
rules: [
//css-loader 解析文中@import,style-loader 再以style方式插入样式
//less 下载less less-loader,scss 下载node-sass sass-loader
{
test: /\.(css|less)$/,
use: ['style-loader','css-loader','less-loader']//顺序不能变,不然报错
}
]
},
复制代码
module.exports = {
plugins: [require('autoprefixer')]
}
复制代码
let MiniCssExtractPlugin = require(mini-css-extract-plugin)
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader, //抽取样式到Link标签中 mini-css-extract-plugin
{
loader: 'css-loader',
options: {}
},
'less-loader',
'postcss-loader' //兼容前缀
]
}
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css' //href名字,以下图所示
})
]
复制代码
目标:把ES6语法或者更高级别语法编译成ES5语法react
{
test: /\.js$/,
exclude: 'node_modules',
use:
[
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
"plugins": [
['@babel/plugin-proposal-decorators',{"legacy":true}],//解析装饰器
['@babel/plugin-proposal-class-properties',{"loose":true}],
[ "@babel/plugin-transform-runtime"] //该插件依赖安装@babel/runtime,解析高级语法,好比yiled
]
}
},
'eslint-loader' //根目录新建.eslintrc.json 配置代码规则 add eslint eslint-loader -D
],
exclude: /node_modules/
}
复制代码
yarn add babel-polyfill 解析实例上的高级语法,在index中import进去 若是引入jquery,全局引用的话,暴露$,module中配置expose-loaderjquery
{
test: require.resolve('jquery'),
use: {
loader: 'expose-loader?$',
}
}
复制代码
引入图片有三种方式: 1:new Image() 2.css background:url() 3.html中建立 yarn add file-loader html-withimg-loader -Dwebpack
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader' //解决html中引入img不识别图片的问题
},
{
test:/\.(png|jpg|gif)$/,
use: 'file-loader' //会自动建立一个MD5戳的名字,而后把图片拷贝到打包后的dist
}
]
}
复制代码
可是图片过多会引发资源请求过多,所以url-loader会优化这个问题 yarn add url-loader -Dgit
{
test:/\.(png|jpg|gif)$/,
//url-loader会调用file-loader,优化:避免过多发请求,把小的图片或icon转换成base64,体积变大,不适用大图片
//use: 'file-loader' //会自动建立一个MD5戳的名字,而后把图片拷贝到dist
use: {
loader: 'url-loader',
options: {
limit: 8*1024 //小于8k的图片会转换成base64,避免请求
}
}
}
复制代码
output:{},
watch:true,//实时监控
watchOptions:{
poll:1000,
aggregateTimeout: 2000,//若是2秒内没动做,自动打包, 防抖
ignored:/node_modules/
},
module:{}
复制代码
resolve: {
modules: [path.resolve('node_modules')],//只查找当前路径的node_modules
extensions: ['.js','.less','.json','.css'],//引入文件时省略扩展名
alias: {//别名
componets: './src/components/'
}
}
复制代码
1.每次打包后都会生成新的dist目录,clean-webpack-plugin 自动清空打包后的目录
let CleanWebpackPlugin = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin('./dist'),
]
复制代码
let webpack = require('webpack')
plugins:[
new Webpack.DefinePlugin({ //定义环境变量
PRODUCTION:JSON.stringify('dev') // 定义PRODUCTION 是 dev环境
})
new Webpack.BannerPlugin('make by jeffywin'),//版权声明,自带插件
]
复制代码
当mode为production的时候,默认css是不压缩的,须要插件,直接在module.export中配置optimization
let UglifyJsPlugin = require('uglifyjs-webpack-plugin')
let OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
optimization: {//优化
minimizer: [//mode必须是production才有做用
new UglifyJsPlugin({
cache: true,
parallel: true //并行,加速压缩
}),
new OptimizeCssAssetsPlugin({})//压缩css
]
}
复制代码
在一般的打包过程当中,你所引用的好比bootstrap、react、react-router、antd、vue、vue-router、vuex 等等众多库每次开发打包都会打包进dist目录中,随着文件愈来愈大,打包的时间和代码体积也愈来愈大,因为这些库的内容基本不会发生改变,每次打包加入它们无疑是一种巨大的性能浪费。所以DllPlugin的出现就是解决这一问题,用某种方法实现了拆分 bundles,同时还大大提高了构建的速度。
let path = require('path')
let webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
react: ['react','react-dom',...]
},
output: {
filename: '_dll_[name].js', // 打包后的名字
path: path.resolve(__dirname,'dist'),
libraryTarget: 'commonjs2',
libraryTarget: 'var',
library: '_dll_[name]'//打包后会自动添加var _dll_[name] = {},来拿到内部的react,暴露出 (也叫作放入全局域) dll 函数
},
plugins:[
new webpack.DllPlugin({//声明动态连接库
name: '_dll_[name]', //暴露出的 DLL 的函数名
path: path.resolve(__dirname,'dist','mainfest.json')//manifest json 文件的绝对路径 (输出文件)
})
]
}
复制代码
运行 yarn run build -- --config webpack.dll.js,会生成两个文件
new ReferencePlugin({//开发优化 减小打包体积
manifest:path.resolve(__dirname,'dist','mainfest.json') //html中还须要全局引用
})
复制代码
manifest包含 content 和 name 的对象,或者在编译时(compilation)的一个用于加载的 JSON manifest 绝对路径,也就是引用DllPlugin打包后的文件
按需打包前
总结: webpack.dll.js:DllPlugin 打包生成打包后的文件 和 mainfest.json关系映射文件
webpack.config.js: 主配置文件DllReferencePlugin经过mainfest映射到json文件,json文件调用提早打包好的缓存文件
当项目比较大时,经过happypack插件,它将任务分配给多个子进程去并发执行,子进程处理完再发给主进程,从而减小构建时间,可是项目比较小时,不建议使用,子进程分配时间反而可能增长构建时间。
使用:经过把原来module中的配置移到plugins中
let Happypack = require('happypack')
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=js',
exclude: /node_modules/,
include: path.resolve('src')
}
]
}
plugins: [
new Happypack(
{
id: "js",
use:[{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
"plugins": [
['@babel/plugin-proposal-decorators', { "legacy": true }],//解析装饰器
['@babel/plugin-proposal-class-properties', { "loose": true }],
['@babel/plugin-transform-runtime'] //该插件依赖安装@babel/runtime,解析高级语法,好比yiled
] //es7高级语法,顺序不能变
}
}],
//'eslint-loader' //根目录新建.eslintrc.json 配置代码规则
}
)
]
复制代码
继续优化 yarn add webpack webpack-cli html-webpack-plugin @babel/core babel-loader @babel/preset-env @babel/preset-react
假如项目中引用了jquery等,能够用noParse来不去解析有关的依赖项 还有excludes,includes
module: {
noParse: /jquery/,//不去解析jquery中的依赖项
rules: [
{
test: /\.js$/,
exclude: /node_modules/,//排除
include: path.resolve(src),//包含
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
复制代码
假如引用了moment时间插件,会自动下载本地语言文件,致使打包文件过大,能够用webpack自带插件 webpack.IgnorePlugin
plugins: [
//若是引入了monent,去除掉本地的语言插件,若是须要能够单独引用
new webpack.IgnorePlugin(/\.\/local/,/moment/),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './public/index.html'
})
]
复制代码
配置以后
多页面模块打包抽取公共代码和第三方库 假如同时引入了两个文件,或者jquery等第三方库,而且是多页面打包,能够将公共部分提早抽取出来打包
optimization: {
splitChunks: {
cacheGroups: {
common:{
chunks: 'initial',
minSize: 0, //超过0个字节
minChunks: 2,//用过2次以上就抽离出来
},
venor: {//第三方
priority: 1,//权重,优先抽离
test: /node_modules/,
chunks: 'initial',
minSize: 0, //超过0个字节
minChunks: 2,//用过2次以上就抽离出来
}
}
},
},
复制代码