项目的地址
https://github.com/jianjiache...
内部配置大部分做了详细说明
执行方式:
cnpm install
cnpm run start
cnpm run build
完成的功能
- [x] 分离生产环境与开发环境
- [x] 添加source-map方便调试
- [x] 分析了babel-polyfill不同导入方式的影响
- [x] 代码分割 定义了被抽离的模块如何分成组
- [x] 识别React语法以及ES6
- [x] 处理了不兼容ES7修饰器(@)Decorator的问题
- [x] 加入了less以及sass的处理
- [x] 抽离了所有的css样式文件
- [x] 压缩了JS代码以及CSS代码
- [x] 添加了CSS自动补全浏览器前缀,增强了适配性
- [x] 完成对字体、图片、媒体文件的按大小分类打包策略
- [x] 生成一个HTML文件,并主动加入JS文件
- [x] 配置删除生产环境的console.log
- [x] 每次打包先清除dist目录
- [x] 加入了代码的热更新,修改代码自动编译
- [x] 加入了对包大小的可视化分析工具
需要用到的Webpack内置的配置
给打包出的js文件换个不确定名字
使用webpack内置的[hash]或[chunkhash]
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
module.exports = merge(common, {
mode: 'production',
output: {
filename: 'js/[name].[chunkhash:8].bundle.js',
},
······
});
代码分割
Webpack内置了optimization(优化字段)的splitChunks来实现代码的分割,大多数情况下不需要配置就够用了,但你也可以个性化的配置,
比如你想指定哪些代码该分到哪一组可以使用cacheGroups来配置
module.exports = {
//...
optimization: {
splitChunks: {// 抽离公共代码 具体配置看官网
chunks: 'all',// 效值是all、async和initial。提供all可能特别强大,因为这意味着即使在异步和非异步块之间也可以共享块
minSize: 30000,
maxSize: 0,
minChunks: 1,
cacheGroups: {// 定义了被抽离的模块如何分成组,不然公共代码全打包到一个JS文件里面
vendors: {// 第三方库抽离
priority: 1,// 权重 先进行第三方库抽离
test: /[\\/]node_modules[\\/]/,// 选从node_modules文件夹下引入的模块,所以所有第三方模块才会被拆分出来 递归的
name: "vendor",
enforce: true,
},
}
}
//...
};
自动编译打包
安装webpack-dev-server
npm install webpack-dev-server --save-dev
增加代码至webpack.dev.config.js
:
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
output: {
filename: 'js/[name].[hash:8].bundle.js',
},
devServer: {
contentBase: path.resolve(__dirname, '../dist'),
open: true,
port: 9000,
compress: true,
hot: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
inject: 'body',
hash: false
}),
new webpack.HotModuleReplacementPlugin()
]
});
HotModuleReplacementPlugin
是webpack热更新的插件,设置devServer.hot
为true,并且在plugins中引入HotModuleReplacementPlugin插件即可。
注意的是我们开启了hot,那么导出不能使用chunkhash,需要替换为hash。
修改我们的package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config ./config/webpack.prod.config.js",
+ "start": "webpack-dev-server --inline --config ./config/webpack.dev.config.js"
},
修改代码自动运行
执行代码
npm run start
自动开了一个端口为9000的网页,上面是我们写的页面内容,这和我们的配置都是一一对应的。
现在你随意修改app.js中的代码,再回到页面看下是不是也跟着变了,那我们就整合webpack-dev-server成功!
其他需要用到的插件简介
terser-webpack-plugin
可配置删除console.log
npm install --save-dev terser-webpack-plugin
clean-webpack-plugin
只想要最新打包编译的文件,就需要先清除dist目录
npm install --save-dev clean-webpack-plugin
uglifyjs-webpack-plugin
压缩代码
npm install --save-dev uglifyjs-webpack-plugin
mini-css-extract-plugin
将css提出去,而不是直接在页面来内嵌
npm install --save-dev mini-css-extract-plugin
webpack-bundle-analyzer
可视化的包大小分析工具
npm install --save-dev webpack-bundle-analyzer
其他优化打包的插件使用方式
直接在plugins字段里面new一个实例,参数就是插件的配置项
我就不一一介绍了直接给一个完整的webpack.prod.config配置
const merge = require('webpack-merge'); // 区分生产环境和开发环境
const common = require('./webpack.common.config.js'); // 导入基础配置
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 插件为你生成一个HTML文件,并主动加入JS文件
const TerserPlugin = require('terser-webpack-plugin');// 可配置删除console.log
const {CleanWebpackPlugin} = require('clean-webpack-plugin');// 只想要最新打包编译的文件,就需要先清除dist目录
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');// 压缩代码
const MiniCssExtractPlugin = require('mini-css-extract-plugin');// 将css提出去,而不是直接在页面来内嵌
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');// 将提出去的css压缩
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // 包大小分析工具
module.exports = merge(common, {
mode: 'production',
output: {
filename: 'js/[name].[chunkhash:8].bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,// 单独提出CSS
'css-loader',
'postcss-loader'// 对css编译的工具 可以:1.使用下一代css语法 2 . 自动补全浏览器前缀 3 . 自动把px代为转换成rem
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /\.(scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
},
]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'public/index.html',// 定义的html为模板生成 从根路径开始查找
inject: 'body',
minify: {// 压缩HTML文件
removeComments: true,//去除注释
collapseWhitespace: true,//去除空格
},
}),
new CleanWebpackPlugin(),
new UglifyJsPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[id].[hash].css',
}),
new BundleAnalyzerPlugin({
analyzerPort: 9001,
})
],
optimization: {// 优化
minimizer: [ // 最小化器
new TerserPlugin({// 缩减代码的插件
terserOptions: {
compress: {
drop_console: true, // 删除console.log
},
}
}),
new OptimizeCssAssetsPlugin({// 压缩CSS
assetNameRegExp:/\.css$/g,
cssProcessor:require("cssnano"),// 用于压缩和优化CSS 的处理器
cssProcessorPluginOptions:{
preset:['default', { discardComments: { removeAll:true } }]
},
canPrint:true
})
],
splitChunks: {// 抽离公共代码 具体配置看官网
chunks: 'all',// 效值是all、async和initial。提供all可能特别强大,因为这意味着即使在异步和非异步块之间也可以共享块
minSize: 30000,
maxSize: 0,
minChunks: 1,
cacheGroups: {// 定义了被抽离的模块如何分成组,不然公共代码全打包到一个JS文件里面
vendors: {// 第三方库抽离
priority: 1,// 权重 先进行第三方库抽离
test: /[\\/]node_modules[\\/]/,// 选从node_modules文件夹下引入的模块,所以所有第三方模块才会被拆分出来 递归的
name: "vendor",
enforce: true,
},
}
}
}
});
打包图片字体媒体文件,以及调试优化
下载文件打包的依赖
npm install file-loader url-loader --save-dev
调试devtool里填个cheap-module-eval-source-map,当你保存时能直接找到源文件的多少在报错
下面直接给个一个给个webpack.common.config的配置
const path = require("path");
module.exports = {
devtool: "cheap-module-eval-source-map",// 方便调试
entry: {
// 定义入口文件
index: "./src/index.js"
//index: ['babel-polyfill','./src/index.js'], // 添加polyfill垫片(挂载ES6+的方法和API如Promise等)这是很老的写法被坑了,会污染全局,现在preset-env内置了按需加载
//framework: ['react','react-dom'],// 代码分割 定义分组
},
output: {
// 编译打包之后的文件名以及所在路径
filename: "js/bundle.js",
path: path.resolve(__dirname, "../dist")
},
module: {
// 编译器
//noPars:/jquery/,// 比如我引入了jquery 它不依赖其他的包,就不需要解析 直接打包
rules: [
{
test: /\.(js|jsx)$/, // 代码
use: "babel-loader",
exclude: /node_modules/ // 不需要去转译
},
{
test: /\.(jpg|png|gif)$/, //图片
use: {
loader: "url-loader",
options: {
name: "[name].[ext]",
outputPath: "images/",
limit: 8192 // 大于8Kb走file-loader(好像是自动的不用添加fallback),小的ICON什么的直接打包插入到bundle.js中减少Http请求
/* fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
} */
}
}
},
{
test: /\.(eot|ttf|svg|woff|woff2)$/, // 字体
use: {
loader: "file-loader",
options: {
name: "[name]_[hash].[ext]",
outputPath: "font/"
}
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
use: {
loader: "file-loader",
options: {
name: "[name].[hash:8].[ext]",
outputPath: "media/"
}
}
},
/* {
test: /\.css$/,
use: [
'style-loader',// 最后计算完的css,将会使用style-loader生成一个内容为最终解析完的css代码的style标签,放到head标签里
'css-loader' // css-loader加载器去解析这个文件,遇到“@import”等语句就将相应样式文件引入
]
} */
]
}
};
完整的目录结构
WebpackReact
├── config
│ ├── webpack.common.config.js
│ ├── webpack.dev.config.js
│ ├── webpack.multipleEntry.config.js
│ └── webpack.prod.config.js
├── dist
├── dist备份
│ └── 第一次打包.js
├── font
│ ├── demo.css
│ ├── demo_index.html
│ ├── iconfont.css
│ ├── iconfont.eot
│ ├── iconfont.js
│ ├── iconfont.json
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.woff2
├── image
│ ├── vscode.png
│ ├── 可视化.png
│ ├── 快餐.png
│ ├── 美食.png
│ └── 面包.png
├── package.json
├── postcss.config.js
├── public
│ └── index.html
├── readme.md
├── src
│ ├── app.js
│ ├── app.less
│ └── index.js
├── video
│ └── 110.mp4
└── 笔记.md