重学webpack系列(十一) -- 重学webpack系列终结与展望

688 阅读8分钟

前言

各位同学看到这里,就表明《重学webpack系列》已经更新完毕,这个系列我们一起探讨了一下webpack的核心机制,包括前端模块化的演变历史、webpack所能解决的问题、loaderplugindevServersourceMaphotModuleReplacewebpack的运行机制、高级特性框架的结合使用。这一章我们主要是来讲一下关于webpack的常见面试题与个人的后期创作目标,还是那句话,欢迎点赞关注一溪之石感谢各位。

常见的面试题

一、在项目中让你配置一下Webpack,你应该注意什么?

针对这个问题,关于Webpack的基本配置无疑就是需要modedevtoolentryoutputmoduleplugindevServer几个配置项,mode能够告知Webpack以成熟的预设去帮助打包,entry告知Webpack打包入口是什么文件,output告知Webpack打包输出到哪里,loaderplugin为加载非js文件,Webpack的工程化构建流程提供一套最佳的解决方案,devServer为本地开发提供一个服务器,用于提高开发效率,详见重学webpack系列(零) -- 全局概况,我们还可以配置sourceMapHMR来帮助我们提高开发效率。

二、关于mode的三种预设,你觉得他们之间有什么不同呢?

关于modeWebpack提供了三种预设,分别为:nonedevelopmentproduction

  • none:不会启用Webpack的任何优化插件,基本上不使用。
  • development:自动优化打包速度,启用内置插件更好的捕捉错误,便于代码调试
  • production:启动内置插件优化打包结果,不过打包速度偏慢,便于生产模式访问效率

三、你对loader了解多少,你们常用哪些loader呢,如果让你手写一个loader你有什么想法呢?

loader作为Webpack集成的对非js资源加载、Webpack工程化中功能处理的模块,我们项目中常见于对样式、图片、文字、音频、字体等文件的加载、对代码兼容、缓存等功能的支持所需要的loader如下。

  • style-loader:用于生成一个style标签,把css引入到页面中。
  • css-loader:加载css资源。
  • scss-loader:加载scss资源。
  • postcss-loader:处理css浏览器的兼容,自动加上前缀。
  • eslint-loader:代码规范化。
  • url-loader:加载图片,文字等资源,通过publicPath生成一个路径,供外部成员调用。
  • babel-loader:代码降级,解决兼容问题。
  • ...

如果让我写一个loader,那么我得根据loader的执行要求:我不管loader如何处理逻辑,但是返回的必须是一段可执行的JavaScript代码。

四、你对plugin了解多少,你们常用哪些plugin呢,如果让你手写一个plugin你有什么想法呢?

plugin顾名思义为"插件",它能够帮助我们做一下loader做不到的事情,比如代码压缩打包结果的清除等等,项目中常见的plugin如下。

  • CleanWebpackPlugin:用于在每一次打包生成新的bundle.js之前,清除上一次的打包文件。
  • HtmlWebpackPlugin:用于生成html文件。
  • CopyWebpackPlugin:用于拷贝那些不需要参与打包的文件。
  • MiniCssExtractPlugin:用于提取所有css文件。
  • ProgressBarPlugin:打包可视化进度条。
  • HotModuleReplacementPlugin:可用于热更新。
  • DllReferencePlugin:分包拆包,webpack5中已经不再维护了,推荐使用Webpackoptimization配置项。

如果让我写一个plugin,那么我得根据plugin的执行要求:

  • 每一个插件的本身就是一个函数。
  • 每个函数内部都要实现一个apply方法。
  • 借助webpack生命周期钩子,通过compiler对象访问钩子,帮我们把插件注入到webpack运行流程中执行。
  • 根据需求编写我们的逻辑。

五、loader与plugin的区别在哪呢,你知道有两种引入css的方式吗,他们的区别呢?

loaderplugin的本质都是函数,但是loader要求必须返回可执行的JavaScript代码,而plugin则必须实现一个apply方法,且需要借助Webpack的生命钩子方才能执行,这就是他们最大的区别,其次loader也可以实现构建工程化里面的功能,比如babel-loader,但是按照约定俗成,我们直接把loader成为模块加载器,主要用于资源模块的加载,而plugin能够完成loader不能完成的的事情,只能说他是对loader功能的扩展,且他的功能更加丰富。

两种引入css的方式一种是style-loader,一种是MiniCssExtractPlugin

  • style-loader:生成style标签,引入到页面。
  • MiniCssExtractPlugin:生成link标签,引入到页面。

六、Webpack的optimization有配置过吗?可以简单说说吗?

module.exports = {
    ...
    optimization : {
        splitChunks: {
            // chunks: 'all' || 'async' || 'initial' , all与initial效果类似,async为异步模块
            cacheGroups: {
                commons: {
                    chunks: "initial",//相同的chunks提出来
                    minChunks: 2,//依赖了两个以上的关系
                    minSize: 0 //这个依赖最小体积为0
                },
                vendor: {
                    test: /node_modules/,
                    // 默认选项,表示只要有依赖的第三方包就要拆出去,跟all差不多
                    chunks: "initial",
                    name: "vendor",
                    enforce: true
                }
             }
        },
        usedExports: true, // 只导出外部成员引用模块 
        // 此属性用于模块导入合并,因为单独的模块导入要使用_webpack_require_函数。 
        // 此属性就是可以利用_webpack_require_一次性导入所有模块,也叫作用域提升。 
        concatenateModules: true, 
        minimize: true, // 开启代码压缩,或者配置压缩器
        // minimizer:[ new OptimizeCssAssetsWebpackPlugin() new terser-webpack-plugin() ]
        sideEffect: true,
        
    }
}

七、Webpack的构建原理是怎样的呢?

npm run build就可以让webpack自动打包构建了,然后webpack会经历如下步骤。

  • webpack-cli启动。
  • 载入配置项参数,初始化Compiler对象,加载所有配置项plugin
  • 使用Compiler对象的run方法开始编译项目。
  • 通过entry找到入口文件,解析模块依赖,形成依赖树。
  • 递归遍历依赖树,让loader去加载对应的模块以及依赖模块。
  • 合并loader处理结果,组装成chunks,转换成文件,输出到build目录。

详见重学webpack系列(八) -- webpack的运行机制与工作原理

八、Webpack的HMR原理你知道吗,请简单说说?

HMR就是模块的热更新,核心原理就是创建一个本地服务器,通过与client建立socket链接,当依赖资源有更新的时候,能够实现正在运行中的模块热替换。具体参见重学webpack系列(七) -- webpack的HMR的实践与原理

九、treeShaking知道吗,说说他跟babel-loader是否产生冲突呢?

treeShanking顾名思义就是把代码中,没有被外部成员引用到的代码优化掉,起到压缩的作用,在production中,treeShaking是自动开启的。因为我们知道treeShaking是基于ESM生效的,那么我们在项目中配置了babel-loader会把ESM转为Common.js,那treeShaking是不是就失效了呢,在babel-loader中,禁用了babelESM的转化,所以treeShaking还是能够生效的。

module.exports = {
    ...
    module:{
        rules:[
            {
                test:'js',
                use:{
                    loader: "babel-loader",
                    // 禁止开启对ESM模块的转变
                    options: { presets: [ ['@babel/preset-env', { "modules": false }] ] }
                }
            }
        ]
    }
}

十、你能不能介绍一下Webpack5都新增了哪些特性呢,简单说说吧?

  • webpack5中,mode='production'自动开启。
  • 内置terser-webpack-plugin插件,mode='production'自动压缩。
  • optimization.concatenateModules = true,作用域提升,模块合并。
  • cache-loader废弃,持久化缓存,module.exports = { cache: { type: 'filesystem', // 文件系统 }, }
  • asset module 资源模块代替 file-loaderurl-loader
  • webpack server启动本地服务,详见webpack启动服务
  • ......

十一、你了解Webpack的三种hash吗?请简单说说?

三种hash分别为文件hashchunkhashcontenthash

  • hash : 为打包后所有文件的hash,只要其中一个文件改变,此hash就会改变。
  • chunkhash : 为不同文件的单独hash值,只要本身内容改变就会改变hash值。
  • contenthash : 为不同文件单独hash,只要本身内容改变就会改变hash值,可用于解决外部依赖文件的变更,影响到自身的hash的变化的情况。

十二、Webpack的resolve配置项有用过吗,请简单说说他有什么作用?

可用作指定配置,告知Webpack以什么样的方式去构建,表现在:

  • 别名:alias
  • 文件类型:extensions
  • 解析的模块范围:modules
module.exports = {
    resolve: {
        alias:{
            '@':'root/src' // 指定别名@,通过@可以找到文件目录
        },
        extensions:{
            ['.jsx', '.tsx', '.vue'] // 指定webpack需要解析哪些类型的文件
        },
        modules:{
            ['node_modules', 'root/src'] // 指定webpack需要解析那些范围的文件
        }
    }
}

十三、说一说你在项目中做了Webpack层面的哪些优化呢,以及你所了解的Webpack层面的优化?

详见重学webpack系列(九) -- webpack的高级特性与前端性能优化

展望

这篇文章与上一篇文章更新隔了20多天,下一个系列前端构建工具vite进阶系列,搁浅的也有些时间了,所以接下来的主要创作时间就放在了这个上面,同时也希望跟各位同学一起交流学习心得。