专栏首页前端一会深入webpack4配置笔记(必备/可选配置 单页/多页配置)

深入webpack4配置笔记(必备/可选配置 单页/多页配置)

必备配置

  1. 自动生成html文件,使用html-webpack-plugin 插件
  2. 重新打包时前删除dist目录,然后再执行打包,使用clean-webpack-plugin插件
  3. entryoutput配置,占位符[name]publicPath(比如配置js文件等资源的cdn地址,使得打包后的html中引入的js地址为cdn地址)
  4. 三种提升开发效率的即时打包:watch(使用file协议)、devServer开启本地服务器(使用http协议,需安装webpack-dev-server,本地代码修改后实时打包自动更新刷新页面)、自己用node写服务器(使用http协议,不足是本地代码修改后虽然实时打包但页面仍需手动刷新才能看见最新显示)。除此还可以安装http-server包,然后打包项目到dist目录后,再运行scripts命令"start": "htt-server dist",这样的操作和将项目打包后dist目录丢到服务器上访问类似。
  5. 打包静态文件:
  • 图片 png/jpg/gif等静态图片资源 使用 file-loader 或者 url-loader,推荐使用 url-loader,因为后者可通过 options 进行额外配置
  • css/scss 按顺序使用postcss-loader(配合autoprefixer插件) / sass-loader(依赖node-sass) / css-loader / style-loader 来进行 css3代码前缀自动添加、scss代码转成css代码、插入html页面head的style中
  • css模块化打包 开启css文件模块化打包,可以在某个js文件中 通过 import xxx from "./yyy.scss" 文件来进行模块化打包scss文件,在js中可以通过 xxx.classSelecter来引用某个具体的样式选择器进行样式class的添加
  • 字体文件打包 就是使用file-loader把eot/svg等从src目录移到dist目录
  1. 将ES6/7语法转换为ES5语法,安装babel-loader@babel/core(babel V7开始为@babel)、配置文件.babelrc中配置presets,它使用@babel/preset-env来将ES6/7语法转译成兼容低版本浏览器的兼容代码。如果要编译Promise、部分原型方法可以使用@babel/polyfill,然后通过入口js文件中import @babel/polyfill即可(这种方法会把所有转译ES6/7高级API的兼容代码一口气全打包出来),或者可以在.babelrcpresets@babel/preset-env配置属性对象里添加useBuiltIns: "usage"(这种办法就是按需打包出兼容代码,注意在我当前使用的babelV7版本中此时还需配置corejs版本)。使用@babel/polyfill有个问题,它的兼容代码会污染全局变量,在写普通业务代码项目中没问题,但如果babel用于写组件类库,就需要换个方法来避免污染全局环境:可以使用@babel/plugin-transform-runtime(安装于devDepend)和@babel/runtime-corejs2(安装于depend),然后在.babelrc中配置plugins,它的原理是通过闭包的形式挂载兼容代码,从而不会污染全局变量。babelJavaScript的编译器。
  2. 代码分割(CodeSplitting)/异步引入模块。通过同步引入的模块进行代码分割时需配置optimization.splitChunks对象配置(配置参数看这里,也可以看webpack.common.js中这部分的配置注释);通过异步引入的模块(仅import("xxx module"))则只需在添加@babel/plugin-syntax-dynamic-import这个官方插件并在.babelrc文件中的plugins里配置引入该插件就行,这里要注意异步引入import("xxx module")是一个Promise,可以通过调用then方法执行后续逻辑。
  3. css文件的代码分割:安装插件mini-css-extract-plugin,在生产环境对应的配置文件中const MiniCssExtractPlugin = require("mini-css-extract-plugin");引入该插件后,在plugins中启用该插件,同时设置样式文件loader的最后一步由style-loader替换为MiniCssExtractPlugin.loader。这里有个地方要注意,由于该插件尚未支持HMR功能,所以webpack4建议在生产环境中使用该插件,开发环境开启HMR后就无需配置css代码分割了。
  4. css代码的压缩:安装插件optimize-css-assets-webpack-plugin,引入该插件并配置,可以查看官方文档DOCUMENTATION -> PLUGINS -> MiniCssExtractPlugin -> Minimizing For Production Analysis
  5. 设置webpack打包的环境变量,可以安装cross-env模块并在scripts配置项中设置cross-env NODE_ENV=production,如此可在webpack配置文件中获取当前打包环境变量值。
  6. 开启Hot Module Replacement 热模块更新(HMR), 需配置webpack.config.js文件中两个地方:devServer中配置hothotOnlyHotModuleReplacementPlugin插件
  7. devtool配置sourceMap,它是一种映射关系,用于指出源代码中具体出错位置,弄明白source-mapinline-source-mapcheap-source-map等关系,并给出开发环境与生产环境的devtool的sourceMap配置最佳实践(开发环境为cheap-module-eval-source-map,生产环境为cheap-module-source-map)
  8. developmentproduction模式打包区别,安装第三方模块webpack-merge进行配置文件合并。
  9. 懒加载:通过import异步加载模块就是属于一种懒加载,但是到底什么时候加载这个模块,则取决于什么时候真正执行import语句。借助这种方法,可以更快加载页面。异步加载模块采用ES Module的动态加载ES模块的方法:import()
  10. PreLoading优化:webpack推荐前端js更多使用异步加载来提高页面首次加载速度,这从它的optimization.splitChunks.chunks值默认是async就可以看出,即默认配置只分割异步模块代码,这样打包出来的页面首次加载js只会加载同步代码,异步模块代码会等到满足异步触发条件时再另外加载对应的异步js文件,这样能明显提高页面首次加载的速度和所加载js代码的使用率。分割同步模块代码只能是优化缓存提高页面二次加载时的速度,对页面首次加载速度提升并无帮助。所以优化页面首次、多次加载速度需要分割打包异步和同步模块,分别对应优化页面js代码使用率和缓存。查看js代码使用率可以打开chrome浏览器的控制台 -> Coverage,快捷键是Ctrl + Shift + P。写高性能页面时,重点考虑的应是页面代码的使用率,而不是缓存。
  11. PreFetching优化:当通过Preloading优化的页面加载完毕后,此时带宽释放,可以利用这段空闲的带宽来预先加载异步模块文件,如此当用户交互触发异步加载条件时就会有与一次性加载所有模块一样的响应体验,因为此时浏览器中已经有异步模块文件的缓存。比较典型的案例就是页面加载后点击登录展示登录模态框,当页面首次加载时不会加载登录模态框的模块代码,页面加载完毕后利用带宽释放空档提前加载登录模态框的模块代码文件,如此当用户点击登录按钮时,可以直接调用相应的登录模态模块代码。实现方法是使用到魔法注释 /* webpackPrefetch: true */,使用详情可以访问webpack官方文档的DOCUMENTATION -> GUIDES -> Code Splitting -> Prefetching/Preloading modules。所以如果要提高页面加载性能,可以使用ES Modules异步模块加载来进行懒加载,同时添加Prefetching优化,利用页面主逻辑加载完毕后带宽释放空档提前加载异步模块文件,来达到明显提升页面加载速度的目的。
  12. webpack帮浏览器做合理缓存:在output.filenameoutput.chunkFilename值中添加占位符contenthash,它的意思是当文件内容没变时打包生成文件的hash值不变,如果文件内容变了那么打包生成文件的hash值就会改变。
  13. Shimming预置依赖,指的就是预先配置第三方库垫片,比如jQuery,可以在配置文件plugins数组中添加new webpack.ProvidePlugin({ $: "jQuery" })插件,这样当项目js中用到关键字$时程序就能理解为jQuery对象。
  14. Tree shaking 作用:在模块引入打包中,引入什么就打包什么,未引入的模块代码就会被忽略掉;或者当一个模块文件中会export多个模块,但只被引入某些个模块,另有部分模块可能未被引用时,Tree Shaking 也会把这个模块文件中的未被引用的模块给摇掉,也就是不打包它们,而只打包该模块文件中被引用的那些模块。注意 Tree Shaking只支持ES Module这种模块引入方法,对其他模块引入方式(如CommonJS/AMD等)不起作用。在开发环境中默认不开启,如需开启需配置optimization中的usedExports: true,同时在package.json中配置"sideEffects": false,,意思是Tree Shaking 对所有模块都进行treeShaking操作,这里也可以将值改为数组,数组项即被用来配置需要忽略treeShaking操作的模块,例如在js页面中引入import "@babel/polyfill"时就可以配置"sideEffects": [ "@babel/polyfill" ],。但现在一般不用这样配置,因为已经在.babelrc中配置了"useBuiltIns": "usage"这样表示默认所有js都已添加import "@babel/polyfill"。所以既然页面js中无需做这样的引入,就不需要添加treeShaking默认忽略列表项。当然如果引入的模块是scss或css之类的样式文件模块,则为防止部分样式代码未被引用导致被treeShaking误忽略打包造成不可控错误,可以进行类似sideEffects: [*.css]的配置。(这样在开发环境中就算是配置好Tree Shaking,但是打包后其实仍会将未引入的模块打包进dist里,只是相比未配置,会多加一句注释表明使用的模块是哪些,其原因是为了开发环境下的调试方便,避免因删除未引入模块代码导致的行数错乱从而误导错误提示行数。)在生产环境中Tree Shaking 默认就已经开启了,所以无需配置optimization中的usedExports: true,但还是需要在package.json中配置sideEffects的忽略列表,这里要注意。

可选配置

  1. 打包分析,可以查看打包模块之间的关系,官方提供的可以访问webpack-analyse这个地址,它提供用于生成打包分析的JSON文件的命令,还可在该页面获取可视化分析该JSON文件的入口地址。可将--profile --json > stats.json这个命令片段添加至package.json文件的script脚本命令中,例如"dev-build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js",配置好后运行npm run dev-build命令完成后会在项目根目录生成stats.json文件,这个json文件中会有打包过程的各项信息。可以将这个json文件上传至http://webpack.github.com/analyse查看打包过程信息的可视化展示(注意这个地址说是需要访问外国网站才能访问,不过我即使访问外国网站也不能访问?)。如果上面的官方分析工具始终无法访问,也可以使用其他方法,可以访问webpack官方文档的DOCUMENTATION -> GUIDES -> Code Splitting -> Bundle Analysis查看其他分析工具,推荐使用Webpack Bundle Analyzer
  2. webpack构建项目的js模块文件中的this默认指向模块本身,而不是指向window对象,如果要想将this指向window对象,需要通过imports-loader来解决。
  3. 用webpack打包库代码,方法与打包业务代码差不多,只是在output配置中添加libraryTarget: "umd"library: library,前者作用是为打包后的库添加支持ES ModuleAMDCMD模块引入方式,后者作用是当库代码直接被页面用<script />引入时提供一个名为library的全局变量,可以用于访问库代码中的方法。另外当自身库代码依赖其他第三方库代码时,比如依赖lodash库时,可以在配置文件中添加externals: [ "lodash" ],这样可以在打包自身库代码时忽略打包lodash的代码,这样就能通过不打包进第三方库代码来减小自身库代码体积,而当他人引用自身库代码时,也只需在其代码中引入lodash库依赖就可以使用我们发布的库了。发布npm库:npm addusernpm publish,注意要修改包管理文件package.json中的main属性值为打包生成的目标文件。
  4. PWA打包配置。webpack打包生成的dist文件通常最后是丢到服务器上供访问,如想在本地体验这种丢服务器上测试可以本地安装http-server,然后当打包完成后再运行scripts命令"start": "htt-server dist",这样的操作和将项目打包后dist目录丢到服务器上访问类似。PWA指实现当服务器挂掉/断网时浏览器本地可利用缓存继续访问该服务器中的原网页,有更好的用户体验。首先安装workbox-webpack-plugin,在生产环境配置文件中引入(无须用于开发环境)并在plugins中配置该插件。除此以外,还要在入口js中写些业务代码来实现PWA,看下面 if( "serviceWorker" in navigator ){ // 如果浏览器支持serviceWorker window.addEventListener( "load", ()=>{ navigator.serviceWorker.register( "/service-worker.js" ) .then( registration=>{ console.log( "service-wroker registed" ); } ) .catch( err=>{ console.log( "service-worker register error" ); } ) } ) }
  5. webpack打包配置TypeScript,首先安装npm i -D ts-loader typescript,然后配置文件中添加ts-loader配置,其次在根目录添加tsconfig.json配置文件进行相应ts配置,了解ts配置可以查看这里。如果在.tsx文件中引入lodash或者jquery这样的第三方库使用,为了仍能使用ts的错误检查警告这个优势(例如ts中对方法参数的校验),需要安装第三方库对应的typescript类型文件检查包,例如使用lodash需要安装@types/lodash,使用jquery需要安装@types/jquery,如果对于要安装对应类型检查文件包不清楚,可以点击这里进行搜索。

webpack打包性能优化

  1. 提高webpack打包速度: a. 升级新的webpack版本、Node和npm版本; b. 在尽可能少的模块上应用loader(通过include或者exclude去约定只有某些文件夹下的模块被引入时才使用对应loader,从而降低该loader被执行频率,以此更少量执行该loader的转化或编译执行过程); c. 尽可能少使用plugin,同时确保plugin的可靠性; d. resolve参数合理配置,例如resolve: { extensions: [ ".js", ".jsx" ] },它作用是当引入文件不写后缀时通过该配置从左到右依次查找对应后缀的文件。不过注意这里需要合理配置,不要滥用,如果添加项太多,会导致打包查找文件时增加性能损耗。约定资源性文件如图片要写后缀.png,而逻辑性的如jsx则加下。 e. 使用DllPlugin提高打包速度:由于第三方模块通常长期不变,所以只在首次打包第三方模块时分析该模块代码,其他时候打包不会分析该第三方模块代码,以此加快打包速度。可以点击这里查看DllPlugin官方配置文档; f. 控制包文件大小,对于未使用到的包可以通过Tree Shaking或者不引用等方法降低包大小; g. 多进程打包; h. 合理使用sourceMap,通常越详细的sourceMap打包的越慢; i. 结合stats分析打包结果; j. 开发环境内存编译; k. 开发环境无用插件剔除;

多页面打包配置

使用webpack4打包多Html页面的配置是在上面基础上,特别的利用Html-webpack-plugin,这里给出一个配置方案仅供参考:

const path = require( "path" );
const HtmlWebpackPlugin = require( "html-webpack-plugin" );             // 用于生成html文件的插件  

// 配置入口对象与html-webpack-plugin实例集合,约定对应html的js与html同名以便自动化生成入口对象
const entries = {};     // 保存文件入口
const pages = [];       // 存放html-webpack-plugin实例
(function () {
    let pagePath = path.join( __dirname, "src/views" );     // 定义存放html页面的文件夹路径,此处值为 F:\modules\webapck4\w4-2\src\views
    let paths = fs.readdirSync(pagePath);                   // 获取pagePath路径下的所有文件,此处值为 [ 'about.html', 'index.html', 'list.html', 'main.html' ]
    paths.forEach( page=>{
        page = page.split( "." )[0];        // 获取文件名(不带后缀),例: [ 'about', 'html' ],当前page值就为字符串about
        pages.push( new HtmlWebpackPlugin( {
            filename: `views/${page}.html`,     // 生成的html文件的路径(基于出口配置里的path)
            template: path.resolve( __dirname, `src/views/${page}.html` ),      // 参考的html模板文件
            chunks: [ page, "common", "vendors", "manifest" ],       // 配置生成的html引入的公共代码块 引入顺序从右至左
            // favicon: path.resolve(__dirname, 'src/img/favicon.ico'),            // 配置每个html页面的favicon
        } ) );
        entries[page] = path.resolve( __dirname, `src/js/${page}.js` );     // 入口js文件对象
    } )
})();

module.exports = {
    entry: entries,
    /*... 其他配置略 */
    plugin: [
        // 展开所有 new HmtlWebpackPlugin 生成页面的配置对象
        ...pages,
    ]
}

目录结构如下:

本文分享自微信公众号 - 前端小二(frontendxiao2),作者:小二君

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 《深入浅出Node.js》:node的模块规范与模块实现

    Node的目标是成为一个构建快速、可伸缩的网络应用平台,通过通信协议来组织许多Node,非常容易通过扩展来达成构建大型网络应用的目的。

    前端_AWhile
  • jQuery源码研究:模块规范兼容

    从jq官网down下最新的未压缩版代码并打开后,首先看下整体,这就是一个大型的自执行的匿名函数:

    前端_AWhile
  • 编写可维护代码4:不轻易修改对象方法

    本篇主要讲下对象的属性与方法的修改问题。由于js中修改对象的属性和方法简直容易至极,所以任何人都可以更改js中的具有可访问可修改权限的对象。这就带来极大的风险,...

    前端_AWhile
  • android值得珍藏的6个开源框架技术

    1、volley  项目地址 https://github.com/smanikandan14/Volley-demo JSON,图像等的异步下载; 网络请...

    xiangzhihong
  • 【芯片救德国】博世10亿欧元建世界最先进芯片工厂,2021年正式投产

    新智元
  • 什么是5G?关注MWC 2019前你需要了解这些知识

    5G 的研发已有将近十年,终于快要变成现实。2018 年,运营商开始在选定城市中实施固定(fixed)5G,2019 年美国将出现移动 5G,预计 2020 年...

    机器之心
  • 英特尔与微软抢夺人工智能领地

    据外媒报道,英特尔与微软正处于一场人工智能的投资狂潮中。这两家芯片与软件巨头在本周内通过各自的风投部门——英特尔投资与微软创投——宣布了一系列交易。 ? 这些交...

    人工智能快报
  • iOS开发中解决报错之the file had a tree conflict

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

    用户1451823
  • 关于webpack的面试题总结

    本文首发于前端面试总结@知乎专栏,各位可以通过点击文章下方的阅读原来来访问原文地址

    用户1687375
  • html图像标签、绝对路径和相对路径

    像网页上插入图片这种外部文件,需要定义文件的引用地址,引用外部文件还包括引用外部样式表,javascript等等,引用地址分为绝对地址和相对地址。

    Devops海洋的渔夫

扫码关注云+社区

领取腾讯云代金券