玩转webpack(二)—— 进阶篇 清疚 2023-06-08 06:36 106阅读 0赞 ## 1. 自动清理构建目录产物 ## 每次在构建的时候不会清理目录,这会造成构建的输出目录的输出文件越来越多 * 通过npm scripts清理构建目录 在每次构建前先删除`dist`目录,可在`package.json`中的`scripts`配置: rm -rf ./dist && webpack 或 rimraf ./dist && webpack 但是这种方法需要手动操作 * 通过`clean-webpack-plugin`插件自动清理构建目录 这个插件会在每次构建的时候删除output指定的输出目录 const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { output: { filename: ...., path: __dirname + '/dist' //clean-webpack-plugin插件会自动清除这个目录 }, plugins: [ new CleanWebpackPlugin(); ] } ⚠️为啥上面引入插件是 `{ CleanWebpackPlugin }`? `clean-webpack-plugin`([https://github.com/johnagan/clean-webpack-plugin][https_github.com_johnagan_clean-webpack-plugin]) 在5.29的时候发布了3.0版本,用法变了。 -------------------- ## 2. 自动补齐css3样式前缀 ## * css3的属性为什么需要前缀? 因为浏览器的标准并没有完全统一 。 <table> <thead> <tr> <th>浏览器内核</th> <th>css3前缀</th> </tr> </thead> <tbody> <tr> <td>Trident</td> <td>-ms</td> </tr> <tr> <td>Geko</td> <td>-moz</td> </tr> <tr> <td>Webkit</td> <td>-webkit</td> </tr> <tr> <td>Presto</td> <td>-o</td> </tr> </tbody> </table> // 比如给一个元素设置border-radius属性 .box{ -moz-border-radius: 10px; -webkit-border-radius: 10px; -o-border-radius: 10px; border-radius: 10px; } 手动添加很麻烦 * 通过使用autoprefixer插件自动补齐css3的前缀 这是代码生成后再进行后缀处理 autoprefixer需要配合`postcss-loader`使用 `npm i postcss-loader autoprefixer -D` module.exports = { // .... module: { rules: [ { test: /\.less$/, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { plugins:() => [ require('autoprefixer')({ browsers: ['last 2 version', '> 1%', 'iOS 7'] // 兼容浏览器版本 }) ] } } ] } ] } } -------------------- ## 3. 移动端CSS的px转换成rem ## 页面适配问题 * 以前通过css媒体查询实现响应式布局 缺点:需要写多套适配样式代码 @media screen and (max-width: 980px) { .header { width: 900px; } } @media screen and (max-width: 480px) { .header { height: 400px; } } @media screen and (max-width: 350px) { .header { height: 300px; } } rem是什么? W3C对rem的定义: font-size of the root element rem是相对单位 px是绝对单位 [点击查看rem em px的区别 >>][rem em px_] * 使用`px2rem-loader`将px转换成rem * 页面渲染时需要计算根元素的font-size的值 * 可以借助手淘的lib-flexible库 * [https://github.com/amfe/lib-flexible][https_github.com_amfe_lib-flexible] * `npm i px2rem-loader -D` * `npm i lib-flexible -S` * html 的script需要引入安装的lib-flexible库的代码(下面会讲怎么将库资源内联近代码) module.exports = { module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader', { loader: 'px2rem-loader', options: { remUnit: 75, // rem相对于px转换的倍数 1rem = 75px remPrecision: 8 // px转换为rem小数点的位数 } } ] } ] } } -------------------- ## 4. 静态资源内联 ## 资源内联的意义: * 代码层面: 页面框架初始化脚本 上报相关打点 css内联避免页面闪动 * 请求层面: 减少HTTP网络请求数 小图片或字体内联(url-loader) 一、HTML和JS的内联 都使用raw-loader 因为内联进来的代码可能存在一些ES6的属性,所以需要先使用babel-loader进行转换在内联进去 * 内联HTML <script>${require('raw-loader!babel-loader!./meta.html')}</script> * 内联JS(比如上述需要内联的lib-flexbile库) <script>${require('raw-loader!babel-loader!../node_modules/lib-flexible')}</script> 二、CSS内联的两种方案 * 借助style-loader加参数 module.exports = { // .... module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader', options: { insertAt: 'top', //样式插入到<head>标签内 singleton: true // 是否将所有的style标签合成一个 } }, 'css-loader' ] } ] } } * 使用html-inline-css-webpack-plugin插件 `npm i html-inline-css-webpack-plugin -D` ⚠️使用这个插件内联css,那么就不会单独抽离css了,则mini-css-extract-plugin将失效 const HtmlInlineCssWebpackplugin = require('html-inline-css-webpack-plugin').default; module.exports = { // .. plugins: [ new HtmlInlineCssWebpackplugin() ] } -------------------- ## 5. 多页面应用打包方案 ## 每次页面跳转的时候,后台服务器都会返回一个新的html文档,这种类型的网站就是多页网站,也叫做多页应用。 * 多页应用的优势: 每个页面之间是解藕的 对SEO更加友好 * 在webpack里如何打包多页面: 1. 每个页面对应一个entry,一个html-webpack-plugin 这样的缺点:每次增加一个页面都需要更改webpack配置 1. 动态获取entry和设置html-webpack-plugin数量(利用glob.sync) `entry: glob.sync(path.join(__dirname, './src/*/*.js'))` `npm i glob -D` -------------------- ## 6. 使用sourcemap ## * 作用: 通过source map可以定位到源代码(方便调试) * 开发环境默认开启,线上环境默认关闭 source map关键字: * eval: 使用eval包裹模块代码 * source-map: 产生.map文件 * cheap: 不包含列信息(比如报错时候会定位到多少行多少列,使用cheap就只能定位到多少行,无法定位到多少列) * inline-source-map: 将.map作为DataURI嵌入,不单独生成.map文件(将.map文件inline进了输出文件最后一行) * module:包含loader的sourcemap 使用: module.exports = { devtool: 'eval' } 如果不开启source map在带啊嘛中打断点无法定位到源代码,而是会定位到打包后到代码,不方便调试。 -------------------- ## 7. 提取公共资源 ## * 基础库分离, * 比如:将react react-dom基础包通过cdn引入,不导入bundle中 * 方法一:使用html-webpack-externals-plugin将基础包通过cdn引入,不打入bundle中 * webpack4内置的一个功能非常大的插件代替了CommonsChunkPlugin插件 chunks参数说明: * async 异步引入的库进行分离(默认) * initial 同步引入的库进行分离 * all 所有引入的库进行分离(推荐) // 以下是默认参数值 module.exports = { optimization : { splitChunks : { chunks: 'async', minSize: 30000, // 抽离的公共包最小的大小 maxSize: 0, minChunks: 1, // 公共文件最小使用次数(大于这个值才会提取成公共文件) maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 } } } } } -------------------- ## 8. tree shaking(摇树优化) ## (对模块代码静态分析) * 概念:一个模块可能有多个方法,只要其中某个方法使用到了,则整个文件都会被打到bundle里面去,tree shaking就是只把用到的方法打入bundle,没用到到方法会在uglify阶段被擦出掉。 * 使用:webpack4默认支持,在`.babelrc`里面设置`modules: false`即可, 在`production mode`的情况下默认开启 * 要求:必须是ES6的语法,CJS的方式不支持 * 理解DCE(Dead Code Elimination) ->无用代码擦除 无用代码举例: * 代码不会被执行,不可到达 * 代码执行的结果不会被用到 * 代码只会影响死变量(只读不写) if(false) { console.log(这段代码永远不会被执行到); } * tree shaking原理: * 1.利用 ES6模块的特点: * 只能作为模块顶层的语句出现 * import 的模块只能是字符串常量 * import binding是immutable的 * 2.代码擦除: * uglify阶段无用代码擦除 -------------------- ## 9. Scope Hoisting使用和原理分析 ## * 存在现象: 构建后的代码存在大量闭包代码 [https_github.com_johnagan_clean-webpack-plugin]: https://github.com/johnagan/clean-webpack-plugin [rem em px_]: https://blog.csdn.net/weixin_43572937/article/details/102611124 [https_github.com_amfe_lib-flexible]: https://github.com/amfe/lib-flexible
还没有评论,来说两句吧...