Webpack是模块打包工具,是工程化,自动化思想在前端开发中的体现,
1.1.1、初始化一个项目
项目安装 (推荐)新建一个文件夹并进入,init
是初始化命令,-y
参数可以免去中间的配置过程,直接一步初始化成功。
npm init -y
1.1.2、安装webpack,
i
是install
的简写,-D
是--save-dev
的简写,仅在开发环境才用的包,会被注册在package.json里的devDependencies
里-S
是--save
的简写,会打包到生成的包里面,是发布内容的一部分,会被注册在package.json里的dependencies
里npm i -D webpack webpack-cli
1.1.3、如果想通过命令执行npm run dev来启动webpack,需要在package.json里加入下面代码。”scripts“的对象里可以配置一些打包命令。dev
是命令的名称,webpack
是打包命令具体执行的语句,--config
是指定配置的文件,紧跟在后面的是配置文件名。详见下文章节 >> 1.3、开发及生产环境分离
"scripts": {
"dev": "webpack --config ./webpack.config.dev.js",
},
1.1.4、新建src
文件夹,目录结构如下图。 新建src/index.js
,这是入口文件,写业务代码的地方
// index.js
console.log("hello webpack")
1.1.5、执行打包命令npm run dev
后,成功后会发现在目录下多了一个dist文件夹,目录如下图,里面有个main_xxxxxx.js
,能打包成功是因为有下文1.1.6的配置
1.1.6、在根目录下新建文件webpack.config.dev.js,输入下面的默认配置,path
是必备的配置项目绝对路径的插件,__dirname
指当前文件的绝对路径
const path = require("path");
module.exports = {
// 必填 webpack执行打包的唯一入口
entry: {
main: [path.resolve(__dirname, './src/index.js')],
},
output: {
// 将所有依赖的模块合并输出到main_xxxxxx.js,xxxxxx为随机生成的6位hash码
//当内容有改变时,hash会变化,防止缓存原因导致修改不更新
filename: 'js/[name]_[hash:6].js',
// 输出文件的存放路径, 必须是绝对路径
path: path.resolve(__dirname, "./dist")
}
}
1.2.1,-entry
指定webpack打包入口,webpack执行构建的第一步将从entry
开始
//多入口 entry是个对象,最终会在输出的文件夹里生成两个文件,base.js和main.js
entry:{
// 解释在下文章节 >> 3.3 、Babel处理ES6
base: ['core-js/stable', 'regenerator-runtime/runtime'],
main: [path.resolve(__dirname, './src/index.js')],
}
1.2.2, -output
打包转换后的文件输出到磁盘位置:
// 多入口的处理
output: {
filename: "[name][hash:6].js", // 利用占位符,文件名称不重复
path: path.resolve(__dirname, "dist") // 输出文件到磁盘的目录,必须是绝对路径
}
1.2.3,-mode
Mode用来指定当前的打包环境
production
生产模式development
开发模式如果没有设置,webpack会将mode的默认值设置为production
1.2.4, -loader
模块解析,模块转换器
webpack是模块打包工具,而模块不仅仅是js,还可以是css,图片或者其他格式
但是webpack默认只处理js
和json
,其他模块就需要用loader
了
1.2.5, -module
模块配置,在webpack里一切皆模块,用来配置需要的匹配规则及使用哪种loader
转换器
module:{
rules:[
test:/\.xxx$/,//指定匹配规则
use:{
loader:'xxx-load'//指定使用的loader
}
]
}
在根目录下新建2个文件,分别是webpack.config.dev.js和webpack.config.pro.js.
修改package.json文件里的"scripts"指令
dev
是在开发环境下,生成一个dist目录的文件夹server
是在开发环境下,在浏览器中打开一个热更新的页面build
是在生产环境下,生成一个build目录的文件夹zip
是在生产环境下,打一个zip压缩包"scripts": {
"dev": "webpack --config ./webpack.config.dev.js",
"server": "webpack-dev-server --config ./webpack.config.dev.js --env.debug",
"build": "webpack --config ./webpack.config.pro.js",
"zip": "webpack --config ./webpack.config.pro.js --env.zip"
},
loader:file-loader
原理是把打包入口中识别出的资源模块,移动到输出目录,并提供输出目录的地址用于替换资源中的原始路径
场景:用file-loader
处理,txt,svg,csv,excel,
图片资源等等
npm i -D file-loader
//代码放入文件webpack.config.dev.js webpack.config.pro.js
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
//use使用一个loader可以用对象,字符串,两个loader需要用数组
use:{
loader: "file-loader",
//options额外的配置,比如资源名称
options: {
//placeholder 占位符 [name]老资源模块的名称 [ext]老资源模块的后缀
name: "[name]_[hash].[ext]",
//打包后存放的位置
outputPath: "images/"
}
}
},
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
use: "file-loader",
}
]
}
url-loader是file-loader的加强版本 npm i -D url-loader
url-loader内部使用了file-loader
,但是遇到小于10000,即8kb的png、jpg、jpeg、gif
文件会转换成base64格式的字符串,并打包到css和js里。对于小体积的图片比较适合
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name]_[hash].[ext]",
outputPath: "images/",
//小于10000,即8kb,才转换成base64
limit:10000
}
}
}
]
}
扩展插件,在webpack打包流程中的特定时机注入扩展逻辑,来改变打包结果,或者做你想要的事情。
htmlwebpackplugin
会在打包结束后,自动生成一个html文件,并把打包生成的js模块引入到该html中
npm i -D html-webpack-plugin
配置,新建src/index.html文件,title引用了htmlWebpackPlugin
配置的标题,方便在webpack的配置中直接修改标题
<title><%= htmlWebpackPlugin.options.title %></title>
//代码放入文件webpack.config.dev.js webpack.config.pro.js
module.exports = {
plugins: [
new htmlWebpackPlugin({
title: "My App", //标题
filename: "index.html",//输出的文件名,默认是index.html
template: "./src/index.html"//模板文件路径
})
]
}
清理上次打包生成的dist
无用代码
npm i -D clean-webpack-plugin
//代码放入文件webpack.config.dev.js webpack.config.pro.js
const {
CleanWebpackPlugin } = require("clean-webpack-plugin")
plugins:[
new CleanWebpackPlugin({
//打包之前清理一次,删掉上次打包生成的dist文件夹
cleanOnceBeforeBuildPatterns: [
path.resolve(__dirname,'./dist')
]
})
]
每次改完代码都需要重新打包一次,打开浏览器刷新,很麻烦。使用webpack-dev-server
来实时刷新页面,代码刚改完,页面就刷新完成了。
npm i -D webpack-dev-server
在package.json文件中的指令为
"scripts": {
"server": "webpack-dev-server --config ./webpack.config.dev.js --env.debug",
}
在webpack.config.dev.js配置
//代码放入文件webpack.config.dev.js
module.exports = {
devServer: {
contentBase: "./dist",//指定被访问html页面所在的目录的
open:true,// 指运行npm run server指令后,自动在浏览器里打开一个页面
port:8081 // 指定打开的页面的端口为8081,也可以指定其他端口
}
}
前后端分离,wepack搞定开发期mock测试数据,启动一个本地服务,mock
多个接口,首先安装express
和fs
npm i express fs -D
//data1.js
module.exports = function(app){
app.get('/api',function(req,res){
res.jsonp({
name:'lisi',age:11})
})
app.get('/api/about',function(req,res){
res.jsonp({
name:'zhangsan',age:40})
})
}
//data2.js
module.exports = function(app){
app.get('/api/home',function(req,res){
res.jsonp({
name:'李四',age:11})
})
app.get('/api/list',function(req,res){
res.jsonp({
name:'张三',age:40})
})
}
在src目录下新建server
执行文件,用来自动加载刚才新建的测试数据,这里的代码无需修改,即可自动加载全部的接口及数据。
// server.js
const express = require('express') //nodejs的web框架
const app = express() //实例化框架
const fs = require('fs') //操作文件的模块
const dir = './server' //接口路径
//readdirSync 该方法返回一个包含指定目录下所有文件名称的数组对象
const list = fs.readdirSync(dir).map((v) => {
require(dir + '/' + v)(app) //拼接出文件路径后,导入执行,同时传入app
})
app.listen('9092') //监听端口
在命令行里进入src文件夹后,再运行指令node server.js,出现跨域报错时,通过修改webpack.config.js
设置服务器代理的方法解决
devServer:{
...
proxy: {
//凡是api这个接口,都会被代理到target的路径上
'/api': {
target: 'http://localhost:9092',
//发送请求头host会被设置为target
changeOrigin:true
}
}
}
在业务代码里,就能通过上面的数据接口,读取到返回的jsonp数据了。
Babel是javascript编译器,能将ES6代码转换成ES5代码,下面安装
npm i babel-loader @babel/preset-env -D
npm i core-js regenerator-runtime -S
babel-loader
是webpack与babel的通信桥梁,@babel/preset-env把es6转成es5@babel/preset-env
里包含了es6,7,8转es5的规则core-js/stable
和regenerator-runtime/runtime
,core-js@3
的详细介绍请看https://www.cnblogs.com/sefaultment/p/11631314.html//代码放入文件webpack.config.dev.js webpack.config.pro.js
entry:{
//导入core-js@3的转译代码,实现了完全无污染的API转译,非常有潜力
base:['core-js/stable','regenerator-runtime/runtime'],
main:[path.resolve(__dirname, './src/index.js')]
//打包成功后,会生成两个文件,base.js和main.js
},
output:{
filename: "js/[name]_[hash:6].js",// 多模块导出,[name]指entry中的base和main,[hash:6]指生成6位hash值
path:path.resolve(__dirname, './dist')
},
module:{
rules: [
{
test:/\.jsx?$/,//适配js和jsx
use: {
loader: 'babel-loader'
}
}
]
}
"browserslist": [
"> 1%", //全球超过1%使用的浏览器
"last 2 versions" //所有的浏览器兼容到最近的2个版本
]
按需加载,减少冗余,根目录下新建.babelrc文件,
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"corejs": 3,//新版本需要指定核心库版本
"useBuiltIns": "usage" //按需注入
}
]
]
}
css-loader
分析css模块之间的关系,并合成一个cssstyle-loader
会吧css-loader生成的内容,以style挂载到页面的head部分sass-loader
把sass语法转换成csspostcss-loader
样式自动添加前缀npm i -D style-loader css-loader sass-loader node-sass postcss-loader postcss-preset-env
//代码放入文件webpack.config.dev.js webpack.config.pro.js
module: {
rules: [
{
test: /\.(css|scss)$/,
//loader是有顺序的,从后往前
use:[
'style-loader',//在页面插入css样式
'css-loader',//抽取css样式
'postcss-loader',//样式前缀自动补全
'sass-loader' //sass当做css技术栈
]
}
]
}
根目录下新建postcss.config.js
const postcssPresetEnv = require('postcss-preset-env')
module.exports = {
plugins: [
//使用postcss为样式自动补齐浏览器前缀,浏览器的版本限制在package.json里的browserslist配置
postcssPresetEnv(),
]
}
cinclude:path.resolve(__dirname, "./src")
resolve.modules用于配置webpack去哪些目录下寻找第三方模块,默认是[‘node_modules’],我们的第三方模块都安装在了项目根目录下,就可以直接指明这个路径
//代码放入文件webpack.config.dev.js webpack.config.pro.js
module.exports = {
resolve:{
modules: [path.resolve(__dirname, "./node_modules")]
}
}
resolve.alias配置通过别名来将原导入路径映射成一个新的导入路径
//代码放入文件webpack.config.dev.js webpack.config.pro.js
resolve:{
alias: {
react: path.resolve(
__dirname,
"./node_modules/react/umd/react.production.min.js"
),
"react-dom": path.resolve(
__dirname,
"./node_modules/react-dom/umd/react-dom.production.min.js"
)
}
}
resolve.extensions在导入语句没带文件后缀时,webpack会自动带上后缀,去尝试查找文件是否存在,但是在查找的时候,会耗费一定的打包时间,默认值:
extensions:['.js','.json','.jsx','.ts']
//代码放入文件webpack.config.dev.js
module.export = {
watchOptions: {
//不监听的node_modules目录下的文件
ignored: /node_nodules/,
}
}
采用这种方法优化后,Webpack消耗的内存和CPU将会大大减少
自动及时更新代码,自动重编译,只适合开发模式。
//代码放入文件webpack.config.dev.js
devServer: {
hot:true,
hotOnly:true,//即便HMR不生效,浏览器也不自动刷新,就开启hotOnly
}
plugins:[
new webpack.HotModuleReplacementPlugin()
]
源代码与打包后的代码的映射关系,通过sourceMap定位到源代码关闭的话可以在配置文件里devtool: “none”
//代码放入文件webpack.config.dev.js
devtool:"cheap-module-eval-source-map",// 开发环境配置
//线上环境不推荐开启
项目中的第三方库,基本不更新,打包的时候分离出来,提升打包速度。
//代码放入文件webpack.config.dev.js
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
plugins = [
new HardSourceWebpackPlugin()
]
会在页面中添加一个按钮,点击会出现一个调试器,输出console信息,及各种报错信息
npm i -D vconsole-webpack-plugin
在文件webpack.config.dev.js中加入如下代码
//代码放入文件webpack.config.dev.js
const vConsolePlugin = require("vconsole-webpack-plugin")
plugins:[
new vConsolePlugin({
enable: true,
filter: ['base']
})
]
单独生成css,可以和js并行下载,提高页面加载效率,与HMR热模块替换冲突,所以只在mode为production模式下打包使用
npm i mini-css-extract-plugin -D
//代码放入文件webpack.config.pro.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module:{
reles: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name]_[contenthash:6].css",
chunkFilename: "[id].css"
})
]
npm i -D cssnano optimize-css-assets-webpack-plugin
//代码放入文件webpack.config.pro.js
new OptimizeCSSAssetsPlugin({
cssProcessor: require("cssnano"),//引入cssnano配置压缩选项
cssProcessorOptions: {
discardComments: {
removeAll: true }
}
})
//代码放入文件webpack.config.pro.js
new htmlWebpackPlugin({
title: "My App", //标题
filename: "index.html",//输出的文件名,默认是index.html
template: "./src/index.html"//模板文件路径
minify: {
//压缩HTML文件
removeomments: true,//移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行符
minifyCss: true //压缩内联css
}
})
“摇树”,清除无用css,js(Dead Code)
npm i glob-all purify-css purifycss-webpack -D
//代码放入文件webpack.config.pro.js
const PurifyCss = require("purifycss-webpack")
const glob = require("glob-all")
plugins:[
// 清除无用 css
new PurifyCss({
paths: glob.sync([
// 要做 CSS Tree Shaking 的路径文件
path.resolve(__dirname, './src/*.html'),// 请注意,我们同样需要对 html 文件进行 tree shaking
path.resolve(__dirname, './src/*.js')
])
})
]
只支持import方式引入,不支持commonjs的方式引入
//代码放入文件webpack.config.pro.js
optimization:{
usedExports: true //哪些导出的模块被使用了,再做打包
}
//package.json
”sideEffects“:false,//正常对所有模块进行tree shaking
//或者在数组里排除不需要tree shaking的模块,应采用数组排除,不然css抽取为单独文件将失效
// 仅生产模式有效,需要配合usedExports
”sideEffects“:["*.css","*.scss","core-js","regenerator-runtime","*.jpg","*.png","*.gif",'react','react-dom']
打包后,如果只生成一个main.js的话,代码体积很大,不利于下载,没有合理利用浏览器资源。使用代码分割后,根据配置会生成几个文件,可以同时下载,充分利用了浏览器的资源。
//代码放入文件webpack.config.pro.js
optimization:{
splitChunks: {
chunks: "all", // 所有的 chunks 代码公共的部分分离出来成为一个单独的文件
cacheGroups:{
//缓存组
react: {
test: /react|react-dom/,
name: 'react',
minChunks: 1,
}
}
}
}
分割前输出的文件结构见上面章节 >> 1.1.5
分割后输出的文件结构如下,多分出来了react_xxxxxx.js及其他
基于 tinypng.com 封装的一个支持nodejs、命令行 和webpack的图片压缩工具。首先需要去
https://tinypng.com/developers这个网站申请key,申请方法为:获取并输入全名和邮箱,点击按钮就会生成API key,拷贝到项目配置中。
npm i -D tinypng-webpack-plugin
在文件webpack.config.pro.js中加入如下代码
//代码放入文件webpack.config.pro.js
const tinyPngWebpackPlugin = require("tinypng-webpack-plugin")
plugins:[
new tinyPngWebpackPlugin({
key: [
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
],
ext: ['png','jpeg','jpg']
})
]
把最后生成的文件夹打包成zip压缩包
npm i -D filemanager-webpack-plugin
在webpack.config.pro.js文件中加入如下代码
//代码放入文件webpack.config.pro.js
const FilemanagerWebpackPlugin = require("filemanager-webpack-plugin")
plugins:[
new FilemanagerWebpackPlugin({
onEnd: {
copy: [//拷贝代码
{
//拷贝代码的源,即我们打包生成的文件夹
source:path.resolve(__dirname, './build'),
//拷贝到一个临时的文件夹里
destination: path.resolve(__dirname,'./tmp_for_zip/dist')
}
],
archive: [
{
//生成压缩包的源,即是我们刚刚拷贝的文件夹
source:path.resolve(__dirname,'./tmp_for_zip'),
//压缩后的包名及格式
destination: path.resolve(__dirname,'./dist.zip')
}
],
//删除刚刚新建的临时文件夹
delete: [path.resolve(__dirname,'./tmp_for_zip')]
}
})
]
└─src
│
└─sprite
│
├─img1
│ a.png
│ b.png
│
└─img2
c.png
d.png
npm i -D postcss-sprites postcss
在文件postcss.config.js中,添加如下代码
const path = require('path')
const sprites = require('postcss-sprites')
const postcss = require('postcss')
module.exports = {
plugins: [
sprites({
filterBy: ({
path: imgPath }) => {
//非sprite文件夹下的图片不合并
const [first, second] = path.dirname(imgPath).split(path.sep).reverse()
return first == 'sprite' || second === 'sprite'
? Promise.resolve()
: Promise.reject()
},
groupBy: ({
path: imgPath }) => {
//以sprite文件夹下的子目录作为分组,子目录下的图片和合并成一张雪碧图
const [first, second, third] = path
.dirname(imgPath)
.split(path.sep)
.reverse()
const {
name } = path.parse(imgPath)
if (first === 'sprite') {
return Promise.resolve(`${
second}-${
name}`)
} else if (second === 'sprite') {
return Promise.resolve(`${
third}-${
first}`)
} else {
return Promise.reject()
}
},
hooks: {
onUpdateRule: (
rule,
token,
{
coords, ratio, spriteWidth, spriteHeight, spriteUrl }
) => {
//start:修改自postcss-sprites/lib/core中的updateRule方法
const posX = -Math.abs(coords.x / ratio)
const posY = -Math.abs(coords.y / ratio)
const sizeX = spriteWidth / ratio
const sizeY = spriteHeight / ratio
token
.cloneAfter({
type: 'decl',
prop: 'background-image',
value: `url(./${
spriteUrl})`,
})
.cloneAfter({
prop: 'background-position',
value: `${
posX}px ${
posY}px`,
})
.cloneAfter({
prop: 'background-size',
value: `${
sizeX}px ${
sizeY}px`,
})
//end:修改自postcss-sprites/lib/core中的updateRule方法
//start:若原始样式中没有设置width或height,则根据图片大小自动添加width或height属性
const dimensions = ['width', 'height']
rule.some(({
prop }) => {
dimensions.some((targetProp, idx) => {
if (prop === targetProp) {
dimensions.splice(idx, 1)
}
})
})
dimensions.forEach((prop) => {
const val = coords[prop]
rule.insertAfter(
rule.last,
postcss.decl({
prop: prop,
value: `${
val}px`,
})
)
})
//end:若原始样式中没有设置width或height,则根据图片大小自动添加width或height属性
},
},
relativeTo: 'rule',
spritePath: './src/img',
spritesmith: {
padding: 4,
},
stylesheetPath: './src/css',
}),
],
}
通过上面的代码把css里的px转换成了rem,在index.html的head中加入下面的代码,即可兼容不同屏幕
<script>
document.documentElement.style.fontSize =
(document.documentElement.clientWidth || document.body.clientWidth) /
7.5 +
'px'
window.addEventListener('resize', () => {
document.documentElement.style.fontSize =
(docuemnt.documentElement.clientWidth || document.body.clientWidth) /
7.5 +
'px'
})
</script>
需文件postcss.config.js中的如下代码配合
npm i -D postcss-px2rem
const px2rem = require('postcss-px2rem')
module.exports = {
plugins: [
px2rem({
remUnit: 100,
}),
]
在webpack.config.dev.js文件里放入如下代码
const path = require('path')
const webpack = require('webpack')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
const vConsolePlugin = require('vconsole-webpack-plugin')
const htmlWebpackPlugin = require('html-webpack-plugin')
const {
CleanWebpackPlugin } = require('clean-webpack-plugin')
const devConfig = (debug) => ({
entry: {
base: ['core-js/stable', 'regenerator-runtime/runtime'],
main: [path.resolve(__dirname, './src/index.js')],
},
output: {
filename: 'js/[name]_[hash:6].js',
path: path.resolve(__dirname, './dist'),
},
// mode:"development",
mode: 'development',
module: {
rules: [
{
test: /\.(css|scss)$/,
include: path.resolve(__dirname, './src'),
//loader是有顺序的,从后往前
use: [
'style-loader', //在页面插入css样式
'css-loader', // 抽取css样式
'postcss-loader', // 样式前缀自动补全
'sass-loader', // sass当做css技术栈
],
},
{
test: /\.jsx?$/, //适配js和jsx
include: path.resolve(__dirname, './src'),
use: {
loader: 'babel-loader',
},
},
{
test: /\.(png|jpe?g|git)$/,
include: path.resolve(__dirname, './src'),
//use使用一个loader可以用对象,字符串,两个loader需要用数组
use: {
loader: 'file-loader',
//options额外的配置,比如资源名称
options: {
//placeholder 占位符 [name]老资源模块的名称 [ext]老资源模块的后缀
name: '[name]_[hash:6].[ext]',
//打包后存放的位置
outputPath: 'images/',
},
},
},
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
include: path.resolve(__dirname, './src'),
use: 'file-loader',
},
],
},
devtool: 'cheap-module-eval-source-map',
watchOptions: {
//不监听 node_modules 目录下的文件
ignored: /node_modules/,
},
resolve: {
modules: [path.resolve(__dirname, './node_modules')],
alias: {
react: path.resolve(
__dirname,
'./node_modules/react/umd/react.production.min.js'
),
'react-dom': path.resolve(
__dirname,
'./node_modules/react-dom/umd/react-dom.production.min.js'
),
},
extensions: ['.js'],
},
devServer: {
contentBase: './dist',
open: true,
port: 8081,
hot: true,
hotOnly: true, //即便HMR不生效,浏览器也不自动刷新,就开启hotOnly
proxy: {
'/api': {
target: 'http://localhost:9092',
changeOrigin: true,
},
},
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HardSourceWebpackPlugin(), //缓存文件
new vConsolePlugin({
enable: debug,
filter: ['base'],
}),
new htmlWebpackPlugin({
title: 'My App', //标题
filename: 'index.html', // 输出的文件名,默认是index.html
template: './src/index.html', // 模板文件路径
}), //插件配置
new CleanWebpackPlugin({
//打包之前清理一次
cleanOnceBeforeBuildPatterns: [
path.resolve(__dirname, './dist'),
path.resolve(__dirname, './build'),
],
}),
],
})
module.exports = (env) => {
//env为在指令中配置的参数,--env.debug,参见上文章节 >> 1.3、开发及生产环境分离
let debug = null
if (env && env.debug) debug = env.debug //如配置了--env.debug参数,则开启vConsolePlugin
return devConfig(debug)
}
在webpack.config.pro.js文件中放入如下代码
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const PurifyCss = require('purifycss-webpack')
const glob = require('glob-all')
const tinyPngWebpackPlugin = require('tinypng-webpack-plugin')
const FilemanagerWebpackPlugin = require('filemanager-webpack-plugin')
const htmlWebpackPlugin = require('html-webpack-plugin')
const {
CleanWebpackPlugin } = require('clean-webpack-plugin')
const proConfig = (zip) => ({
entry: {
base: ['core-js/stable', 'regenerator-runtime/runtime'],
main: [path.resolve(__dirname, './src/index.js')],
},
output: {
filename: 'js/[name]_[hash:6].js',
path: path.resolve(__dirname, './build'),
},
// mode:"development",
mode: 'production',
module: {
rules: [
{
test: /\.(css|scss)$/,
include: path.resolve(__dirname, './src'),
//loader是有顺序的,从后往前
use: [
// 'style-loader',//在页面插入css样式
MiniCssExtractPlugin.loader,
'css-loader', // 抽取css样式
'postcss-loader', // 样式前缀自动补全
'sass-loader', // sass当做css技术栈
],
},
{
test: /\.jsx?$/, //适配js和jsx
include: path.resolve(__dirname, './src'),
use: {
loader: 'babel-loader',
},
},
{
test: /\.(png|jpe?g|git)$/,
include: path.resolve(__dirname, './src'),
//use使用一个loader可以用对象,字符串,两个loader需要用数组
use: {
loader: 'file-loader',
//options额外的配置,比如资源名称
options: {
//placeholder 占位符 [name]老资源模块的名称 [ext]老资源模块的后缀
name: '[name]_[hash:6].[ext]',
//打包后存放的位置
outputPath: 'images/',
},
},
},
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
include: path.resolve(__dirname, './src'),
use: 'file-loader',
},
],
},
resolve: {
modules: [path.resolve(__dirname, './node_modules')],
alias: {
react: path.resolve(
__dirname,
'./node_modules/react/umd/react.production.min.js'
),
'react-dom': path.resolve(
__dirname,
'./node_modules/react-dom/umd/react-dom.production.min.js'
),
},
extensions: ['.js'],
},
optimization: {
usedExports: true, //哪些导出的模块被使用了,再做打包
splitChunks: {
chunks: 'all', //所有的chunks代码公共部分分离出来成为一个单独的文件
cacheGroups: {
//缓存组
react: {
test: /react|react-dom/,
name: 'react',
minChunks: 1,
},
},
},
},
plugins: [
new PurifyCss({
// 清除无用css
paths: glob.sync([
// 要做css Tree Shaking的路径文件
path.resolve(__dirname, './src/*.html'),
path.resolve(__dirname, './src/*.js'),
]),
}),
new OptimizeCssAssetsPlugin({
//压缩css
cssProcessor: require('cssnano'), //引入cssnano配置压缩选项
cssProcessorOptions: {
discardComments: {
removeAll: true },
},
}),
new MiniCssExtractPlugin({
//提取css为单独文件
filename: 'css/[name]_[contenthash:6].css',
}),
new tinyPngWebpackPlugin({
key: [
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
'----------这里填入申请到的API key--------',
],
ext: ['png', 'jpeg', 'jpg', 'gif'],
}),
zip
? new FilemanagerWebpackPlugin({
onEnd: {
copy: [
{
source: path.resolve(__dirname, './build'),
destination: path.resolve(__dirname, './tmp_for_zip/dist'),
},
],
archive: [
{
source: path.resolve(__dirname, './tmp_for_zip'),
destination: path.resolve(__dirname, './dist.zip'),
},
],
delete: [path.resolve(__dirname, './tmp_for_zip')],
},
})
: () => {
},
new htmlWebpackPlugin({
title: 'My App', //标题
filename: 'index.html', // 输出的文件名,默认是index.html
template: './src/index.html', // 模板文件路径
minify: {
//压缩HTML文件
removeomments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行符
minifyCss: true, //压缩内联css
},
}), //插件配置
new CleanWebpackPlugin({
//打包之前清理一次
cleanOnceBeforeBuildPatterns: [
path.resolve(__dirname, './dist'),
path.resolve(__dirname, './build'),
],
}),
],
})
module.exports = (env) => {
//env为在指令中配置的参数,--env.debug,参见上文章节 >> 1.3、开发及生产环境分离
let zip = null
if (env && env.zip) zip = env.zip//如配置了--env.zip参数,则打一个zip的压缩包
return proConfig(zip)
}
https://github.com/hyj0703/webpack