webpack常见面试题

162 阅读4分钟

wabpack是做什么的?

概念webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容

原理: 从入口开始递归的开始读取模块所依赖的的文件内容,生成AST树,然后遍历AST树,输出让浏览器能够运行的代码到dist文件夹

loader与plugin的区别

webpack将一切都视为模块,但是webpack原生只能解析js文件和json文件,如果要解析其他类型的文件就要用到loader,所以loader相当于翻译官的作用,将其他类型的文件进行预处理

Plugin为插件的意思,Plugin可以扩展webpack的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,帮助webpack做一些事情。

loader有些什么注意事项

  1. 单一原则,一个loader只能做一个事情
  2. 多个loader会按照从右至左的顺序执行

例如:

['css-loader', 'vue-style-loader'] // 会先执行vue-style-loader然后再执行css-loader

常用的plugin

  • html-webpack-plugin这个插件会创建一个html文件,并且会自动的引入打包好的文件资源
  • mini-css-extract-plugin 打包过后的css在js文件里,该插件可以把css单独抽出来

怎么利用webpack来优化网页性能

  • 资源文件压缩
  • Tree Shaking
  • 代码分离
  • 动态导入代码(懒加载、预获取)
  • 缓存

资源文件压缩

webpack默认在生产模式中的就会压缩js代码,css压缩可以使用CssMinimizerWebpackPlugin这个插件

Tree Shaking

Tree Shaking中文含义是摇树,在webpack中指的是打包时把无用的代码摇掉,以优化打包结果,而webpack5已经自带了这个功能了,当打包环境为production时,默认开启tree-shaking功能。

代码分离

将公共资源提取出来,打包成一个文件,optimization中进行如下配置

optimization: {
    splitChunks: {
        chunks: 'all'
    }
}

动态导入代码(懒加载、预获取)

懒加载:当用到某个模块的时候才加载 预获取:当浏览器空闲的时候采取获取资源

缓存

浏览器具有缓存机制,当不更改文件名的时候,浏览器会认为你没有更新,就会使用缓存版本

具体实现:

  • 缓存第三方库,将第三方库提取到单独的Vendorchunks的文件中,利用浏览器的长效缓存机制,命中缓存来消除请求,在optimization.splitChunks添加cacheGroups参数
  • 业务代码文件不缓存,在output中的filename设置为[name][contenthash].js,contenthash会根据文件的内容生成一个hash的字符串

如何提高代码构建速度

  • 优化loader配置,缩小处理范围:合理利用这两个属性exclude:不需要处理的文件 和 include:需要处理的文件
  • HMR(Hot Module Replacement) 模块热替换只重新构建发生变化的模块
  • babel缓存 第二次构建时,会读取之前的缓存,只重新构建变化的文件
  • 使用Dll进行分包
  • 多进程打包

优化loader配置

在使用loader时,可以通过配置includeexcludetest属性来匹配文件,接触includeexclude规定哪些匹配应用loader

在配置 babel-loader 时,如下:

module.exports = {
  module: {
    rules: [
      {
        // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
        test: /\.js$/,
        // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
        use: ['babel-loader?cacheDirectory'],
        // 只对项目根目录下的 src 目录中的文件采用 babel-loader
        include: path.resolve(__dirname, 'src'),
      },
    ]
  },
};

模块联邦

我们知道webpack可以通过dll实现对同一个项目的公共组件模块,做成代码共享common chunk,但是如果是要实现跨项目针对不同的应用就变得非常的困难不易实现。几乎没办法做到不同应用之间进行插拔式的热更新。那怎么样去实现这种跨应用间的共用模块运用呢?于是乎webpack5内置了一个模块联邦的功能特性,这个功能可以让跨应用间做到模块共享真正的插拔式的便捷使用。比如a应用如果想使用b应用中list的组件,通过模块联邦可以直接在a中进行import('b/list')非常的方便

模块联邦配置使用

new ModuleFederationPlugin({
  // 当前应用的名称, 需要唯一性
  name: "main_app",
  // 入口文件名称, 用于对外提供模块时候的入口文件名
  filename: "remoteEntry.js",
  // 需要导出的模块, 用于提供给外部其他项目进行使用
  exposes: {
    "./search": "./src/search/search.vue"
  },
  // 需要依赖的远程模块, 用于引入外部其他模块
  remotes: {
    lib_remote: "lib_remote@http://localhost:8085/remoteEntry.js",
  },
  // 配置共享的组件, 一般是对第三方库做共享使用
  shared: {
    vue: {
      eager: true,
      singleton: true,
    }
  }
})