webpack (模块打包,代买拆分,资源载入)
-
快速上手
-
webpack4以后新增工作模式
-
webpack.config.js 配置文件中增加 mode: "production development none"
-
命令行增加
webpack --mode production //默认 webpack --mode development webpack --mode none //最原始状态的打包
-
2.资源模块加载 webpack.docschina.org/loaders
-
loader
- file-loader
-
{ test: /.png$/, // use: ['file-loader'] use: ['url-loader'], options: { limit: 10 * 1024 } // url-loader 文件超出会调用file-loader
3.url加载(Data Urls)
- url-loader
- 最佳实践,对项目中小的文件实行Data Urls打包,减少请求次数;大文件单独提取存放,提高加载速度
加载器分类 --loader执行顺序从数组后面往前面执行
- 编译转换类型
- 文件操作类型
- 代码检查
webpack 处理ES2015
-
安装babel-loader
yarn add bable-loader @babel/core @babel/preset-env --dev
-
配置
{ test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset'] } } }
模块加载
-
Es Modules === import
-
commonJs === require
-
Amd标准 === define require
-
html模块加载 webpack会将html文件作为字符串引入
import footerHtml from './footer.html' document.write(footerHtml)
-
html-loader
-
名称 类型 默认值 描述 sources
`{Boolean Object}` true
启用/禁用 sources 处理 preprocessor
{Function}
undefined
允许在处理前对内容进行预处理 minimize
`{Boolean Object}` 在生产模式下为 true
,其他情况为false
通知 html-loader
压缩 HTMLesModule
{Boolean}
true
启用/禁用 ES modules 语法 esModule 配置
-
这个配置项的作用,是指定引入文件的方式,是否指定es module的形式引入(也就是 improt name from ‘url’)这个配置项默认值是true,如果是true的情况下,那再使用require或者****引用方式就会出现上面的问题。
解决方法:把esModule这个配置项配置为false, 或者在js中使用improt语法引入import src from '../cover.jpg'。 但是即使在js中使用了import语法还是解决不了在html中的引用问题。所以可以选择直接把esModule配置为false即可。
-
-
{ test: /.html$/, use: { loader: 'html-loader', options: { esModule: false, sources: { list: [ '...', { tag: 'img', attribute: 'data-src', type: 'src' }, { tag: 'a', attribute: 'href', type: 'src' } ] } } } }
webpack核心工作原理
!(C:\Users\15815\AppData\Roaming\Typora\typora-user-images\image-20211124213209697.png)
开发一个loader
- webpack中loader要求返回的是javascript代码
插件-plugin
-
clear-webpack-plugin
plugins: [new CleanWebpackPlugin()]
-
自动生成 html文件- html-webpack-plugin
- 同时输出多个页面文件,指定模板,添加标题,元信息
module.exports = { mode: 'none', entry: './src/index.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'output') // publicPath: 'output/' // htmlwebpackplugin会自动生成路径 }, module: { rules: [ { test: /.md$/, use: ['html-loader', './markdown-loader.js'] } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: 'html-webpack-plugin', meta: { viewport: 'width=device-width' }, template: './src/index.html' }), new HtmlWebpackPlugin({ // 可通过多个实例生成多个html文件 filename: 'about.html' }) ] }
插件总结-相比loader plugin拥有更宽泛的能力范围
-
通过钩子机制实现
webpack要求plugin输出一个函数或者包含apply方法的对象 class MyPlugin { apply(compiler) { console.log('MyPlugin start') compiler.hooks.emit.tap('MyPlugin', (compilation) => { // compilation => 打包的上下文 for (const name in compilation.assets) { if (name.endsWith('.js')) { const contents = compilation.assets[name].source() console.log(contents) const withoutComment = contents.replace(//*+*//g, '') compilation.assets[name] = { source: () => withoutComment, size: withoutComment.length // 要求包含size 和source方法 } } } }) } }
自动编译、自动刷新
//监听文件变化
//启动时添加参数 --watch
yarn webpack --watch
//全局工具 browser-sync dist --files “**/*”
webpack-dev-server
//安装
yarn add webpack-dev-server
//使用 可加参数 --open
yarn webpack-dev-server --open
// 访问静态额外的资源文件\代理跨域 一般只在生产打包阶段使用// new CopyPlugin({
// patterns: [{ from: 'publice', to: 'dest' }]
// }),
devServer:{
contentBase: './public', // 或者为 [],
proxy: {
'/api': {
// localhost:8080/api/user => https://api.github.com/app/user
target: 'https://api.github.com',
pathRewrite: { // https://api.github.com/app/user => https://api.github.com/user
'^api': ''
},
changeOrigin: true //改写主机名
}
}
}
souce-map 代码映射 源代码地图
-
在代码末尾添加sourcemap文件引用
///# sourceMaoingURL=jquery-3.4.1.min.map
-
配置sourcemap
devtool: 'source-map'
-
webpack支持12不同的soucemap文件
-
sourcemap开发选择 ==== cheap-module-eval-sourcemap
-
sourcemap生产选择 ==== none
-
webpack.config.js输出可为对象或者数组,为数组是会打包输出多套代码
webpack自动刷新的问题-解决方案HMR(Hot Module Replacement)
-
核心问题-自动刷新后页面状态丢失的问题
-
webpack开启HMR-webpack-dev-server中集成
//使用webpack-dev-server 参数开启 webpack-dev-serve --hot // 配置文件开启 const webpack = require('webpack') devServer: { hot: true } new webpack.HotModuleReplacementPlugin()
-
HMR-api
-
通过手动实现js热更新
module.hot.accept('./edit.js', () => { console.log('module更新了') })
-
图片模块热更新
module.hot.accept('./better.png', () => { console.log('module更新了') })
-
HMR注意事项
//每次代码更新后会导致之前的控制台信息刷屏 //解决方案 hot-only // HMR相关代码会在打包阶段被移除 devServer: { // hot: true hotOnly: true }
webpack生产环境优化-mode
webpack生产环境优化-mode
-
根据不同环境配置导出不同配置
-
一个环境对应一个配置文件
1-..
2-..
一般由一个公共配置文件和两个不同环境文件组成
-
由于Object.assign()会完全覆盖掉对象中同名的属性
因此,采用webpack-merg npm模块
-
webpack DefinePlugin-为代码注入全局成员
- DefinePlugin注入的默认为js代码
- 注入值可通过 JSON.stringify()转换
Tree Shaking -- 移除未应用代码 生产模式中会自动引用
* optimization - 开启webpack内部优化配置
* useExports 标记未被引用代码
* minimize 压缩清除未被引用代码
* 
webpack合并模块 concatenateModules (也被成为scope Hoisting 作用域提升)
-
concatenateModule会尽可能的将所有模块合并输出到一个函数中
optimization:{ concatenateModules:true }
-
tree shaking作用的前提示使用EsModule
-
tree shaking 与 babel-loader -- babel-loader将代码转换为 commonjs会导致treeshaking失效
-
配置babel-loader强制使用commonjs使treeshaking失效(modules:false 禁用commonjs转换)
webpack sideeffects新特性(副作用:模块除了导出成员之外还做了其他什么功能,一般开发npm模块时用到)
- 生产环境会自动开启
- package.json中可标明代码无副作用
- sideeffects 注意 可表示有副作用的文件
webpack代码分割
-
多入口打包
-
动态导入
-
多入口打包
entry:{ index: 'index.js', album: 'album.js }, output: { filename: '[name].bundle.js' } //
为页面指定js
webpack-公共模块提取(将公共模块提取到一个文件夹中)
-
optimization:{
splitchunks:{
chunks: 'all'
}
}
2.动态导入--实现按需加载
- webpack会将动态导入的模块分包只有在使用时才加载
webpack 魔法注释
* 相同的chunkname会被打包在一起
* 
MiniCssExtractPlugin-提取css到单个文件
-
style-loader(将样式通过style标签注入)=>
-
MiniCssExtractPlugin通过link注入样式文件,不再需要style.loader
-
问题:webpack生产模式只压缩js文件,css文件需要手动处理
通过使用插件 optimize-css-assets-webpack-plugin
-
webpack官方建议把压缩类插件配置到optimization中的minimize中
optimization:{ minimizer:[ new OptimizeCssAssetsWebpackPlugin() ] } //需将js压缩手动添加回来 optimization:{ minimizer:[ new TerserWebpackPlugin(), new OptimizeCssAssetsWebpackPlugin() ] }
输出文件名 Hash
- [hash]-项目级别 只要一文件改变其他文件名hash值全部改变
- [chunkhash]-chunk级别 --不同的打包入口的文件的改变才会改变此入口文件名的hash值
- contenthash-文件级别 --不同的文件有不同的hash值,文件改动只改变本文件的hash值
- 指定文件hash值长度(默认16位): [chunkhash:8]