Webpack基本配置

Webpack

webpack的五个核心概念:

  1. entry,入口配置,设定webpack以那个文件为入口起点开始打包,分析构建内部依赖图
  2. output,输出配置,设定打包后的资源bundles输出位置以及命名
  3. loader,处理非js文件,webpack只识别js和json文件,因此需要loader将非js文件翻译解析
  4. plugins,执行范围更广的任务,功能扩展,功能强化
  5. mode,分为两种:
    1. development,开发模式,设置代码本地调试运行的环境
    2. production,生产模式,设置代码优化上线运行的环境

初接触

运行指令:

​ 准备工作:

npm init 
npm i webpack webpack-cli -D

​ 开发环境:

webpack ./src/index.js -o ./build/built.js --mode=development
//解读:webpack以当前路径下src文件夹下index.js文件为入口文件,打包输出生成到当前路径下build文件夹下built.js文件,打包环境为开发环境

​ 生产环境:

webpack ./src/index.js -o ./build/built.js --mode=production
//解读:webpack以当前路径下src文件夹下index.js文件为入口文件,打包输出生成到当前路径下build文件夹下built.js文件,打包环境为生产环境

​ 引入时注意需引入打包后的文件

1.webpack能处理js/json文件,不能处理css/img等其他资源
2.生产环境和开发环境将es6模块化编译成浏览器能识别的模块化
3.生产环境比开发环境多一个压缩js代码

样式打包

webpack.config.js — webpack配置文件 — 配置webpack指令运行时的操作 — commonjs的语法

所有构建工具都是基于nodejs平台运行的 — 模块化默认采用commonjs语法

webpack配置语法:

module.exports = {
	//webpack配置
}

注意:项目模块用的ES6模块化,配置用的commonjs

示例

const { resolve } = require('path')

module.exports = {
    entry : './src/index.js',
    output : {
        filename : 'built.js',
        //__dirname --- nodejs变量 --- 表示当前文件的目录的绝对路径
        path : resolve(__dirname, 'build')
    },
    //loader配置
    module : {
        rules : [
            //详细loader配置
            //不同文件必须配置不同loader处理
           {	
               //匹配那些文件
               test : /\.css$/,
               //使用哪些loader配置
               use : [
                   //use数组中从右到左,从下到上 依次执行
                   //创建style标签,将js种的样式资源插入进行,添加到head中生效
                   'style-loader',
                   //将css文件变成commonjs模块加载再js种,内容为样式字符串
                   'css-loader'
               ]
           },
           {
              test : /\.less$/,
               //使用哪些loader配置
               use : [
                   //use数组中从右到左,从下到上 依次执行
                   //创建style标签,将js种的样式资源插入进行,添加到head中生效
                   'style-loader',
                   //将css文件变成commonjs模块加载再js种,内容为样式字符串
                   'css-loader',
                   //将less文件编译成css文件
                   //需要less和less-loader两个包
                   'less-loader'
               ] 
           },
           {
             test : /\.scss$/,
               //使用哪些loader配置
               use : [
                   //use数组中从右到左,从下到上 依次执行
                   //创建style标签,将js种的样式资源插入进行,添加到head中生效
                   'style-loader',
                   //将css文件变成commonjs模块加载再js种,内容为样式字符串
                   'css-loader',
                   //将scss文件编译成css文件
                   //需要scss和scss-loader两个包
                   'scss-loader'
               ]    
           }
        ]
    },
    //plugins配置
    plugins : [
        //详细配置
    ],
    //模式选择 当前为开发模式
    mode : 'development'
    //mode : 'production'
}

html打包

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
//注意下载插件

module.exports = {
    entry : './src/index.js',
    output : {
        filename : 'built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
           //详细loader配置 
        ]
    },
    plugins : [
        //html-webpack-plugin
        //默认创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
        new HtmlWebpackPlugin({
            //复制 './src/index.html'文件 并自动引入打包输出的所有资源
            template : './src/index.html'
        })
    ],
    mode : 'development'
}

图片资源打包

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/index.js',
    output : {
        filename : 'built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.less$/,
                //多个loader处理用use
                use : [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                //处理图片资源
                test : /\.(jpg|png|gif)/,
                //注:url-loader依赖于file-loader,因此此处要下载两个依赖
                loader : 'url-loader',
                options : {
                    //图片小于8kb,就会被base64处理
                    //优点:减少请求数量,减轻服务器压力
                    //缺点:图片体积会更大,导致文件请求速度更慢
                    limit : 8 * 1024
                //注:由于url-oader默认使用es6模块化解析,而html-loader引入图片是commonjs
                //解析时地址会出问题:[object Module]
                //因此,需要关闭url-loader的es6模块化,使用commonjs格式
                    esModule : false,
                    //图片重命名
                    //[hash:10]图片的hash的前10位
                    //[ext]取文件原来扩展名
                    name : '[hash:10].[ext]'
                    
                }
            },
            {
                test : /\.html$/,
                //处理html文件的img文件(负责引入img,从而能被url-loader进行处理)
                loader : 'html-loader',
            }
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        })
    ],
    mode ; 'development'
}

其他资源打包

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/index.js',
    output : {
        filename : 'built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.css$/,
                //多个loader处理用use
                use : [
                    'style-loader',
                    'css-loader',
                ]
            },
            //打包其他资源
            {
                //排除css/js/html资源
                exclude : /\.(css|js|html)/
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            loader : 'file-loader',
             options : {
                    name : '[hash:10].[ext]' 
                }
        })
    ],
    mode ; 'development'
}

devServer

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/index.js',
    output : {
        filename : 'built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.css$/,
                use : [
                    'style-loader',
                    'css-loader',
                ]
            },
            {
                exclude : /\.(css|js|html)/
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            loader : 'file-loader',
             options : {
                    name : '[hash:10].[ext]' 
                }
        })
    ],
    mode ; 'development',
    
    //开发服务器 devServer : 用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
    //特点:只会在内存中编译打包,不会有任何输出
    //启动指令: webpack-dev-server
    devServer : {
    	contentBase : resolve(__dirname, 'build'),
            //启动gzip压缩
        compress : true,
            //端口号
        port : 3000,
            //默认打开
        open : true
	}
}

开发环境基本配置

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                //处理less资源
                test : /\.less$/,
                use : [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                //处理scss资源
                test : /\.scss$/,
                use : [
                    'style-loader',
                    'css-loader',
                    'scss-loader'
                ]
            },
            {
                //处理css资源
                test : /\.css$/,
                use : [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                //处理图片资源
                test : /\.(jpg|png|gif)/,
                loader : 'url-loader',
                options : {
                    limit : 8 * 1024,
                    name : '[hash:10].[ext]',
                    esModule : false,
                    outputPath : 'img'
                }
            },
            {
                //处理html中图片资源
                test : /\.html$/,
                loader : 'html-loader'
            },
            {
                //处理其他资源
                exlude : /\.(js|html|css|css|less|scss|jpg|png|gif)/,
                loader ; 'file-loader',
                options : {
                	name : '[hash:10].[ext]',
                	outputPath : 'media'
            	}
            }
        ]
    },
    plugins : [
        //plugins的配置
        new HtmlWebpackPlugin({
            template : './src/index.html'
        })
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true
    }
    
}

提取css成单独文件

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                //处理less资源
                test : /\.less$/,
                use : [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                //处理scss资源
                test : /\.scss$/,
                use : [
                    'style-loader',
                    'css-loader',
                    'scss-loader'
                ]
            },
            {
                //处理css资源
                test : /\.css$/,
                use : [
                    //取代style-loader,提取js中的css成单独文件
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                //处理图片资源
                test : /\.(jpg|png|gif)/,
                loader : 'url-loader',
                options : {
                    limit : 8 * 1024,
                    name : '[hash:10].[ext]',
                    esModule : false,
                    outputPath : 'img'
                }
            },
            {
                //处理html中图片资源
                test : /\.html$/,
                loader : 'html-loader'
            },
            {
                //处理其他资源
                exlude : /\.(js|html|css|css|less|scss|jpg|png|gif)/,
                loader ; 'file-loader',
                options : {
                	name : '[hash:10].[ext]',
                	outputPath : 'media'
            	}
            }
        ]
    },
    plugins : [
        //plugins的配置
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
        new MiniCssExtractPlugin({
            //对输出css文件进行重命名
            filename : 'css/main.css'
        })
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true
    }
    
}

css兼容性处理

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

//设置nodejs环境变量
process.env.NODE_ENV = 'development'

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                //处理css资源
                test : /\.css$/,
                use : [
                    //取代style-loader,提取js中的css成单独文件
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    //css兼容性处理:postcss --> postcss-loader postcss-preset-env
                    //帮助postcss找到package.json中browserslist里面的配置
                    //通过配置加载指定的css兼容性样式
                    //修改loader的配置
                    {
                        loader : 'postcss-loader',
                        options : {
                            ident : 'postcss',
                            plugins : () => [
                                //postcss的插件
                                require('postcss-preset-env')()
                            ]
                        }
                    }
                ]
            },
            {
                //处理图片资源
                test : /\.(jpg|png|gif)/,
                loader : 'url-loader',
                options : {
                    limit : 8 * 1024,
                    name : '[hash:10].[ext]',
                    esModule : false,
                    outputPath : 'img'
                }
            },
            {
                //处理html中图片资源
                test : /\.html$/,
                loader : 'html-loader'
            },
            {
                //处理其他资源
                exlude : /\.(js|html|css|css|less|scss|jpg|png|gif)/,
                loader ; 'file-loader',
                options : {
                	name : '[hash:10].[ext]',
                	outputPath : 'media'
            	}
            }
        ]
    },
    plugins : [
        //plugins的配置
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
        new MiniCssExtractPlugin({
            //对输出css文件进行重命名
            filename : 'css/main.css'
        })
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true
    }
    
}

package.json配置

"browserslist" : {
	"development" : [
		//兼容最近一个版本的浏览器
		"last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
	],
	"production" : [
        //大于99.8%的浏览器
        ">0.2%",
        //不要已经'死'的浏览器
        "not dead",
        //不要oprea mini
        "not op_mini all"
    ]
}

压缩CSS

const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                //处理css资源
                test : /\.css$/,
                use : [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                ]
            },
        ]
    },
    plugins : [
        new MiniCssExtractPlugin({
            filename : 'css/main.css'
        }),
        //压缩css
        new optimizeCssAssetsWebpackPlugin()
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true
    }
    
}

js语法检查Eslint

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                //语法检查:eslint-loader eslint
                //注:只检查开发人员自身写的代码,无需检查第三方库
                //设置检查规则:
                //package.json中配置eslintConfig选项
         	// airbnb --> eslint-config-airbnb-base eslint eslint-plugin-import
                test : /\.js$/,
                exclude : /node_modules/
                loader : exlint-loader,
                options : {
                	//自动修复
                    fix : true
                }
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
    ],
    mode : 'development'
}

package.json中配置

"browserslist" : {
	"development" : [
		"last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
	],
	"production" : [
        ">0.2%",
        "not dead",
        "not op_mini all"
    ]
},
"eslintConfig" : {
	"extends" ; "airbnb-base"
}

js的兼容性处理

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            //js兼容性处理:babel-loader
            {
                test : /\.js$/,
                exclude : /node_modules/
                loader : 'babel-loader',
                options : {
                    //预设,配置babel如何进行兼容性处理
                    //babel @babel/preset-env @babel/core
                	//基本js兼容性处理 : @babel/preset-env
     //全部js兼容性处理 : @babel/polyfill --> 部分兼容性问题却引入了所有兼容性代码,体积太大
     //需求:按需加载 --> core-js
                    presets : [
                        [
                			'@babel/preset-env',
                			{
                				//按需加载
                				useBuiltIns : 'usage',
                				//指定core-js版本
                				corejs : {
                					version : 3
            					},
            					targets : {
            						chrome : '60',
            						firefox : '60',
            						ie : '9',
            						safari : '10',
            						edge : '17'
            					}
            				}
                		]
                    ]
                }
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
    ],
    mode : 'development'
}

压缩js和html

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            //压缩html代码配置
            minify : {
                //移除空格
                collapesWhitespace : true,
                //移除注释
                removeComents : true
            }
        }),
    ],
    mode : 'production'
    //生产环境自动压缩js代码
}

生产环境基本配置

const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

process.env.NODE_ENV = 'production'

//复用loader
const commonCssLoader = [
	MiniCssExtractPlugin.loader,
    'css-loader',
	{
		loader : 'postcss-loader',
		options : {
			ident : 'postcss',
			plugins : () => [
				require('postcss-preset-env')()
			]
		}
	}
]

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.css$/,
                use : [...commonCssLoader]
            },
            {
                 test : /\.less$/,
                 use : [...commonCssLoader,'less-loader']
            },
            {
                 test : /\.scss$/,
                 use : [...commonCssLoader,'scss-loader']
            },
            //一般来说,一个文件只能被一个loader处理,当出现多个loader处理一个文件时
            //loader执行顺序不能出错
            //先执行eslint,再执行babel
            {
                test : /\.js$/,
                exclude : /node_modules/,
                loader : 'eslint-loader',
                //优先执行
                enforce : 'pre'
                options : {
                    fix : true
                }
            },
            {
                test : /\.js$/,
                exclude : /node_modules/,
                loader : 'babel-loader',
                options : {
                    presets : [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns : 'usage',
                                corejs : { version : 3 },
                                targets : {
                                    chrome : '60',
            						firefox : '60',
            						ie : '9',
            						safari : '10',
            						edge : '17'
                                }
                            }
                        ]
                    ]
                }
            },
            {
                test : /\.(jps|png|gif)/,
                loader : 'url-loader',
                options : {
                    limit : 8 * 1024,
                    name : '[hash:10].[ext]',
                    outputPath : 'img',
                    esModule : false
                }
            },
            {
                test : /\.html$/,
                loader : 'html-loader'
            },
            {
              exclude : /\.(js|css|html|less|scss|jpg|png|gif)/,
              loader : 'file-loader',
              options : {
                  outputPath : 'media'
              }
            }
        ]
    }
    plugins : [
    	new MiniCssExtractPlugin({
    		filename : 'css/main.css'
		}),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
            template : './src/index.html',
            minify : {
                //压缩空格
                collapseWhitespace : true,
                //去除注释
                removeComments : true
            }
        })
    ],
    mode : 'production'
}

package.json中配置

"browserslist" : {
	"development" : [
		"last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
	],
	"production" : [
        ">0.2%",
        "not dead",
        "not op_mini all"
    ]
},
"eslintConfig" : {
	"extends" ; "airbnb-base"
}

性能优化

性能优化需求:
	开发环境:
		1.优化打包构建速度
		2.优化代码调试
	生产环境:
		1.优化打包构建速度
		2.优化代码运行的性能	

优化开发环境的打包构建速度—HMR

HMR --- hot module replacement 热模块替换

一个模块发生变化,只会重新打包这一个模块
const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    //entry : './src/js/index.js',
    //解决html文件由于HMR导致不能热更新问题
    entry : ['./src/js/index.js','./src/index.html'],
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.css$/,
                use : [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                ]
            },
        ]
    },
    plugins : [
        new MiniCssExtractPlugin({
            filename : 'css/main.css'
        }),
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true,
        //开启HMR功能
        //当修改webpack配置,新配置要想生效,必须重新webpack服务
        hot : true
    }
    
}
注意:
	样式文件:可以使用HMR功能,因为style-loader内部实现了
	js文件:默认不使用HMR功能
		解决:修改js代码,添加支持HMR功能的代码
	html文件:默认不使用HMR功能,同时会导致html文件不能热更新
		解决:修改入口文件的配置
		html文件不需要做HMR功能
//js代码支持HMR
//module.hot存在则说明开启了HMR功能
if(module.hot){
    module.hot.accept('需要监听变化的文件路径',() => print())
    //方法会监听print.js文件的变化,一旦发生变化,其他模块不会重新打包构建
    //会执行后面的回调函数
}
//监听几个文件,就写几个?
//可抽离优化

优化开发环境的代码调试—source-map

source-map 
	提供源代码到构建后代码映射的一种技术
	功能:如果构建后代码出错了,通过映射可以追踪源代码错误
	
	source-map配置
	
	[inline-|hidden-|eval-][nosources-][cheap-[modlue-]]source-map
	
	source-map	外部
		错误代码准确信息 和 源代码的错误位置
	inline-source-map	内联
		inline 内联只生成一个内联的source-map
		错误代码准确信息 和 源代码的错误位置
	hidden-source-map	外部
		错误代码错误原因但是没有错误位置
		不能追踪代码错误,只能提示到构建后代码的错误位置
	eval-source-map		内联
		eval 内联每个文件都生成对应的source-map,都在eval
		错误代码准确信息 和 源代码的错误位置
	nosources-source-map	外部
    	错误代码准确信息
    	没有任何源代码信息
    		hidden和nosources就是为了隐藏源代码而诞生的
	cheap-source-map	外部
		错误代码准确信息 和 源代码的错误位置
		但是只精确到行错误,不精确到列
	cheap-modlue-source-map	外部
		错误代码准确信息 和 源代码的错误位置
		
	内联和外部的区别:
		1.外部生成了文件,内联没有
		2.内联构建速度更快
		
	开发环境: 速度快,调试更友好
		速度:eval>inline>cheap>...
			eval-cheap-source-map
			eval-source-map
		调试更友好:
			source-map
			cheap-module-source-map
			cheap-source-map
		
		综合方案:eval-source-map(调试更友好加module,速度更快加cheap)
		
	生产环境: 源代码是否隐藏,调试是不是要更友好
		source-map
		nosources-source-map	全部隐藏
		hidden-source-map	只隐藏源代码,会提示构建后代码错误信息
			由于内联会让代码体积更大,因此生产环境不使用内联
		综合方案 : source-map / cheap-module-source-map
const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    entry : ['./src/js/index.js','./src/index.html'],
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.css$/,
                use : [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                ]
            },
        ]
    },
    plugins : [
        new MiniCssExtractPlugin({
            filename : 'css/main.css'
        }),
    ],
    mode : 'development',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true,
        hot : true
    },
    //代码调试优化
    devtool : 'eval-source-map'
}

优化生产环境中module/rules/loader配置项—oneOf

const { resolve } = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    entry : ['./src/js/index.js','./src/index.html'],
    output : {
        filename : 'js/built.js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            //以下loader只会匹配一个
            //注意:不能有两个配置处理同一个文件
            //因此当有eslint-loader时需提到oneOf外面
            oneOf :	[
                {
                    test : /\.css$/,
                    use : [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                    ]
                },
        	]    
        ]
    },
    plugins : [
        new MiniCssExtractPlugin({
            filename : 'css/main.css'
        }),
    ],
    mode : 'production',
    devServer : {
        contentBase : resolve(__dirname, 'build'),
        compress : true,
        port : 3000,
        open : true,
        hot : true
    },
    devtool : 'eval-source-map'
}

优化生产环境—缓存

1.babel缓存  --- 类比HMR,只编译js代码更改的文件 --- 第二次打包速度更快
2.文件资源缓存 --- 上线代码性能优化
	hash:每次webpack构建时会生成一个唯一的hash值
		问题:js和css同时使用一个hash值
			如果重新打包,会导致所有缓存失效(可是只改动一个文件)
	chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
		问题:js和css的hash值还是一样的
			因为css是在js文件中被引入的,所以同属于一个chunk
	contenthash : 根据文件内容生成hash值,不同文件hash值一定不一样
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        //添加hash:解决强制缓存期间js代码改变却不更新的问题
        filename : 'js/built.[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.js$/,
                exclude : /node_modules/
                loader : 'babel-loader',
                options : {
                    presets : [
                        [
                			'@babel/preset-env',
                			{
                				useBuiltIns : 'usage',
                				corejs : {
                					version : 3
            					},
            					targets : {
            						chrome : '60',
            						firefox : '60',
            						ie : '9',
            						safari : '10',
            						edge : '17'
            					}
            				}
                		]
                    ],
                    //开启babel缓存
                    //第二次构建时,会读取之前的缓存
                    cacheDirectory : true,
                }
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
    ],
    mode : 'production',
    devtool : 'source-map'
}

生产环境优化 — tree shaking摇树

tree shaking --- 去除无用代码
	前提1 : 必须使用es6模块
	前提2 : production环境
	减少代码体积
	
	package.json中配置
		"sideEffects" : false 所有代码都没有副作用(都可以进行tree shaking)
			问题 : 会把css / @babel/polifill文件当作无用文件清理掉
			解决: "sideEffects" : ["*.css"]

生产环境优化 — 代码分割 code-split

code-split --- 分割代码 实现 并行加载 按需加载
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    //单入口
    //entry : './src/js/index.js',
    //需求:js文件分别输出
    //多入口
    entry : {
        main : './src/js/index.js',
        test : './src/js/test.js'
    },
    output : {
        //[name] : 取文件名
        filename : 'js/[name].[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            minify : {
               collapseWhitespace : true,
               removeComments : true
            }
        }),
    ],
    mode : 'production',
}
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            minify : {
               collapseWhitespace : true,
               removeComments : true
            }
        }),
    ],
    //可以讲node_modules中代码单独打包成一个chunk输出
    //会自动分析,多入口文件中是否存在公共文件,如果有会打包成一个单独的chunk
    optimization : {
		splitChunks : {
            chunks : 'all'
        }
    }
    mode : 'production',
}
//通过js代码,让某个文件被单独打包成一个chunk
//import 动态导入语法,能将文件单独打包
//给打包文件取固定名字
import(/* webpackChunkName : 'test' */'文件路径')
	.then(result) => {
    	//文件加载成功
	}
	.catch(() => {
        //文件加载失败
    })

优化—js文件的懒加载和预加载

//import动态导入语法
//注意:懒加载也会进行代码分割
//调用js文件时再加载
document.getElementById('btn').onclick = function(){
    import(/* webpackChunkName : 'test' */'文件路径')
	.then(result) => {
    	result.fn()	
	}
}
//预加载
//import动态语法中添加注释字段 webpackPrefetch : true
//预先加载js文件,但是不执行
/*
与正常加载的区别:
	正常加载为并行加载(同一时间加载多个文件)
	预加载为等其他资源加载完毕,浏览器空闲了再加载资源
注意:预加载的兼容性问题
*/
document.getElementById('btn').onclick = function(){
    import(/* webpackChunkName : 'test', webpackPrefetch : true */'文件路径')
	.then(result) => {
    	result.fn()	
	}
}

优化 — PWA

PWA --- 渐进式网络开发应用程序(离线可访问网页)
	plugin : workbox --> workbox-webpack-plugin
const { resolve } = require('path')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')

module.exports = {
    entry : {
        main : './src/js/index.js',
        test : './src/js/test.js'
    },
    output : {
        filename : 'js/[name].[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new WorkboxWebpackPlugin.GenerateSW({
            /*
            	1.帮助serviceworker快速启动
            	2.删除旧的serviceworker
            	
            	生成一个servicerworker配置文件
            	注意: 在js文件中住粗serviceworker,且注意兼容性问题
            */
            clientsClaim : true,
            skipWaiting : true
        })
    ],
    mode : 'production',
}
//注意:eslint不认识window、navigator全局变量
//解决:修改packange.json中配置

if('serviceworker' in navigator) {
    window.addEventListener('load',() => {
        navigator.serviceworker.register('/service-worker.js')
        	.then(() => {
            //注册成功
        })
        	.catch(() => {
            //注册失败
        })
    })
}
package.json中配置
"browserslist" : {
	"development" : [
		"last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
	],
	"production" : [
        ">0.2%",
        "not dead",
        "not op_mini all"
    ]
},
"eslintConfig" : {
	"extends" : "airbnb-base",
    "env" : {
    	"browser" : true //支持浏览器端全局变量
        //"node" : true 支持node全局变量
	}
}

多进程打包

thread-loader
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    module : {
        rules : [
            {
                test : /\.js$/,
                exclude : /node_modules/
                use : [
                	//开启多进程打包
                	//进程启动时间大概为600ms,进程通信也有开销
                	//工作时间消耗较长,才需要多进程打包
                	'thread-loader',
                	{
                		'babel-loader',
                         options : {
                            presets : [
                                [
                                    '@babel/preset-env',
                                    {
                                        useBuiltIns : 'usage',
                                        corejs : {
                                            version : 3
                                        },
                                        targets : {
                                            chrome : '60',
                                            firefox : '60',
                                            ie : '9',
                                            safari : '10',
                                            edge : '17'
                                        }
                                    }
                                ]
                            ],
                            cacheDirectory : true,
                        }
            		}
                ]
            }
        ]
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
    ],
    mode : 'production',
    devtool : 'source-map'
}

externals — 防止某些包被打包

const { resolve } = require('path')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')

module.exports = {
    entry : {
        main : './src/js/index.js',
        test : './src/js/test.js'
    },
    output : {
        filename : 'js/[name].[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new WorkboxWebpackPlugin.GenerateSW({
            clientsClaim : true,
            skipWaiting : true
        })
    ],
    mode : 'production',
    externals : {
        //拒绝jqury被打包
        jquery : 'jQuery'
    }
}

动态连接库 – dll

//webpack.dll.js
/*
	使用dil技术,对某些库(第三方库,react,vue...)进行单独打包
	运行指令 webpack --config webpack.dll.js
*/

const { resolve } = require('path')
const webpack = require('webpack')

module.exports = {
    //最终打包生成的[name] --> jquery
    //['jquery'] --> 要打包的库是jquery
    entry : {
        jquery  : ['jquery']
    },
    output : {
        filename : '[name].js',
        path : resolve(__dirname, 'dll'),
        library : '[name]_[hash]', //打包的库里面向外暴露的内容叫的什么名字
    },
    plugins : [
        new webpack.DllPlugin({
            name : '[name]_[hash]', //映射库的暴露的内容名称
            path : resolve(__dirname, 'dll/manifest.json') 	//输出文件路径
        })
    ],
    mode : 'production'
}
//webpack.config.js配置
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html'
        }),
        //选择不参与打包的库,同时使用时的名称也改变
        new webpack.DllReferencePlugin({
            manifest : resolve(__dirname, 'dll/manifest.json')
        }),
        //将某个文件打包输出,并在html中自动引入该资源文件
        new AddAssetHtmlWebpackPlugin({
            filepath : resolve(__dirname, 'dll/jquery.js')
        })
    ],
    mode : 'production',
}

webpack配置详解

entry详解

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
	entry : './src/index.js',
	output : {
		filename : 'built.js',
		path : resolve(__dirname, 'build')
	},
	plugins : [ 
		new HtmlWebpackPlugin({
			template : './src/index.html'
		})
	],
	mode : 'development'
}
entry : 
	1.string ---> 单入口文件 打包形成一个chunk, 输出一个bundle	chunk名称默认为main
	2.array	---> 多入口文件 所有入口文件最终只会形成一个chunk,输出一个bundle 默认为main
		注 : 2一般用于开发环境中HMR功能中让html更新生效
	3.object ---> 多入口文件,key 名称,value 路径 
		几个文件几个chunk,对应输出几个bundle chunk名称为key
		
	--> 特殊用法  entry : {
                            index : ['./src/index.js','./src/test.js'],
                            add : ['./src/add.js']
						}
				需求:多入口文件中将多个文件打包成一个chunk时使用

output详解

//const { resolve }  = require('path')

output : {
	//指定名称加目录
	filename : 'js/[name].js',
	//输出文件目录(将所有资源输出的公共目录)
	path : resolve(__dirname, 'build'),
	//所有资源引入公共路径前缀 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
	//一般用于生产环境
	publicPath : '/',
	//非入口文件的chunk名称 --> 非entry的额外chunk --> js的import动态语法/optimization配置
	chunkFilename : '[name]_chunk.js',
	//整个库向外暴露的变量名
	library : '[name]',
	//变量名添加的目标属性 --> 此处绑定在browser上
	libraryTarget : 'window'
	//libraryTarget : 'commonjs' 意为以commonjs格式暴露
}

module详解

//const { resolve }  = require('path')

module : {
 	rules : [
 		//loader配置
 		{
 			test : /\.css$/,
 			//多个loader用use
 			use : ['style-loader','css-loader']
 		},
 		{
 			test : /\.js$/,
 			//单个loader用loader
 			//排除node_modules下的js文件
 			exclude: /node_modules/,
 			//只检查src下的js文件
 			include: resolve(__dirname,'src'),
 			//优先执行
 			//enforce : 'pre',
 			//延后执行
 			enforce : 'post'
 			loader : 'eslint-loader'
 		},
 		{
 			//以下配置只会生效一个
 			oneOf : []
 		}
 	]
 }

resolve详解

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
	entry : './src/index.js',
	output : {
		filename : 'built.js',
		path : resolve(__dirname, 'build')
	},
	plugins : [ 
		new HtmlWebpackPlugin({
			template : './src/index.html'
		})
	],
	mode : 'development',
	//解析模块的配置
	resolve : {
		//配置解析模块的路径别名
		allas : {
			//变量名,代表resolve中的绝对路径
			//优点:简写路径, 缺点: 路径没有提示
			$css : resolve(__dirname,'src/css')
		},
		//配置省略文件路径的后缀名
		extensions : ['.js', '.jsx', '.tsx'],
		//声明解析模块的目录
		modules : [resolve(__dirname,'../../node_modules'),'node_modules']
	}
}

dev Server详解

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
	entry : './src/index.js',
	output : {
		filename : 'built.js',
		path : resolve(__dirname, 'build')
	},
	plugins : [ 
		new HtmlWebpackPlugin({
			template : './src/index.html'
		})
	],
	mode : 'development',
	resolve : {
		allas : {
			$css : resolve(__dirname,'src/css')
		},
		extensions : ['.js', '.jsx', '.tsx'],
		modules : [resolve(__dirname,'../../node_modules'),'node_modules']
	},
	devServer : {
		//运行代码的目录
		contentBase : resolve(__dirname, 'build'),
		//监视contentBase目录下的所有文件,文件变化则reload
		watchContentBase : true,
		
		watchOptions : {
			//忽略文件
			ignored : /node_modules/
		}
		//启动gzip压缩
		compress : true,
		//开启端口号
		port : 5000,
		//域名
		host : 'localhost',
		//自动打开浏览器
		open: 'true',
		//开启HMR功能
		hot : true,
		//不显示启动服务器的日志信息
		clientLogLevel : 'none',
		//除了基本启动信息外,不显示其他内容
		quiet : true,
		//如果出错了,不要全屏提示
		overlay : false,
		//服务器代理 --> 解决开发环境跨域问题
		proxy: {
			//devServer(5000)接收到/api/xxx 的请求,就会把请求转发到另外一个服务器(3000)
			'/api' : {
				target : 'http://localhost:3000',
				pathRewrite : {
					//发送请求时,请求路径重写 : 将/api/xxx --> /xxx(去掉/api)
					'^/api' : ..
				}
			}
		}
	}
}

optimization详解

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')

module.exports = {
    entry : './src/js/index.js',
    output : {
        filename : 'js/built.[contenthash:10].js',
        path : resolve(__dirname, 'build')
    },
    plugins : [
        new HtmlWebpackPlugin({
            template : './src/index.html',
            minify : {
               collapseWhitespace : true,
               removeComments : true
            }
        }),
    ],
    optimization : {
		splitChunks : {
            chunks : 'all',
            //以下结尾默认值,一般不做修改,可以不写
            //分割的chunk最小为30kb
            miniSize : 30 * 1024,
            //最大无限制
            maxSize : 0,
            //要提取的chunk最少被引用一次
            minChunks : 1,
            //按需加载时,并行加载的文件的最大数量为5
            maxAsyncRequests : 5,
            //入口js文件最大并行请求数量
            maxInitialRequests : 3,
            //名称连接符
            automaticNameDelimiter : '~',
            //可以使用命名规则
            name ; true,
            //分割chunk的组
            cacheGroups :  {
            	//node_modules中文件被打包到vendors 组的chunk中, --> vendors~xxx.js
            	//满足上方的公共规则,如 : 大小超过30kb,至少被引用一次
            	vendors : {
            		test : /[\\/]node_modules[\\/]/,
            		//优先级
            		priority : -10
        		},
        		default : {
                    //要提取的chunk最少被引用2次
                    minChunks : 2,
                    //优先级
            		priority : -20,
                    //如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
                    reuseExistingChunk : true,
                }
        	}
        },
    	//将当前模块的记录其他模块的hash单独打包为一个文件 runtime
    	//解决问题 : 修改a文件导致b文件的contenthash变化
    	runtimeChunk : {
            name : entrypoint => `runtime-$(entrypoint.name)`
        },
        minimizer : {
            //生产环境的压缩方案 : js和css
            new TerserWebpackPlugin({
                //开启缓存
                cache : true,
                //开启多进程打包
                parallel : true
                //启用source-map
                sourceMap : true
            })
        }
    }
    mode : 'production',
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟小胖砸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值