1 常见loader和plugin有哪些,二者的区别是什么?

  • 常见loader

    1. babel-loader 把ES6+转义为ES5
    2. ts-loader 把TS编译为JS,并提示类型错误
    3. markdown-loader 把markdown变成html
    4. html-loader 把html变成js字符串
    5. sass-loader 把Sass/Scss变成css(一般与6、7搭配使用)
    6. css-loader 把css变成js字符串(一般与7搭配使用)
    7. style-loader 把js字符串变成style标签(一般与6搭配使用)
    8. postcss-loader 把css变成更优化的css(需要在6之前使用)
    9. vue-loader 把单文件组件变成js模块
    10. thread-loader 用于多进程打包
  • 常用plugin

    1. html-webpack-plugin 用于创建HTML页面并自动引入JS和CSS
    2. clean-webpack-plugin 用于清理之前打包的残余文件
    3. mini-css-extract-plugin 用于将JS中的CSS抽离成单独的CSS文件,以解决js改动导致css重新加载的问题
    4. SplitChunkPlugin 用于代码分包
    5. DllPlugin + DllReferencePlugin 用于避免大依赖被频繁重新打包,大幅降低打包时间(例如react)
    6. eslint-webpack-plugin 用于检查代码中的错误
    7. DefinePlugin 用于在webpack config中添加全局变量
    8. copy-webpack-plugin 用于拷贝静态文件到dist
  • 二者区别

    • loader是文件加载器
      • 功能:能够对文件进行编译(babel)、优化(postcss)、压缩等
      • 运行时机:在创建最终产物之前运行
    • plugin是webpack插件
      • 功能:对webpack功能的扩展,比如定义全局变量、加速编译等
      • 运行时机:在整个打包过程(包括前后)都能运行

2 Webpack如何解决开发时的跨域问题

在开发环境下,用js直接访问后端接口会出现跨域的问题

为了解决这个问题,可以在webpack.config.js中添加如下配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
module.exports = {
	// ...
	devServer: {
		proxy: {
			'/api': {
				target: 'http://target.website.com',
                // 修改请求头的origin(例如8080->target.website.com)
				changeOrigin: true,
                // 可以忽略HTTPS报错
				secure: false,
			}
		}
	}
}

3 如何实现Tree-Shaking

  • 是什么

    • tree-shaking就是让没有用到的js代码不打包,以减小包的体积
  • 怎么做

    • 如何开启

      • webpack.config中将mode设置为production(开发环境没必要tree-shaking)即可
    • 怎么shake

      1. 使用**ES Modules语法**(即ES6的importexport关键字)

      2. CommonJS语法无法tree-shaking(即requireexports语法)

        • 需要给babel-loader添加modules: false选项,禁止babel将代码转译为CommonJS的形式
      3. 引入的时候只引用需要的模块

        • 要写import { isEmpty } from 'lodash-es',因为方便tree-shaking(后缀的es表示这个库是用ES modules写的)

        • 不要写import _ from 'lodash',因为会导致无法tree-shaking无用模块

    • 怎么保证不被shake:在package.json中配置sideEffects,防止某些文件被shake

      1. 例如import了x.js,而x.js只是增加了window.x属性,那么x.js就要放到sideEffects中
      2. 全部被import的CSS也都要放在sideEffects

4 如何提高webpack构建速度

  1. 使用DllPlugin将不常变化的代码提前打包,并复用;如vuereact
  2. 使用thread-loader或HapplyPack(过时)进行多线程打包
  3. 处于开发环境时,在webpack.config中将cache设为true
  4. 处于生产环境时,关闭不必要的环节,比如可以关闭source map(在浏览器调试时能定位源文件代码)

5 webpack和vite的区别

  1. 开发环境

    1. vite自己实现server,**不对代码打包,仅进行路径的映射,**充分利用浏览器对<script type=module>的支持
      • 该server仅仅会改变import的路径,即import {createApp} from 'vue'改为import {createApp} from '/node_modules/.vite/vue.js',这样浏览器就知道去哪里找vue.js了
    2. webpack在开发环境会使用babel-loader基于内存提前打包好,这是其比vite慢的主要原因之一
      • 该server会把vue.js的代码打包进main.js
  2. 生产环境

    1. vite使用rollup + esbuild(go)打包JS代码
    2. webpack使用babel(js)来打包JS代码,比esbuild要慢很多
  3. 文件处理时机

    1. vite只会在请求某个文件时处理该文件(先请求再打包)
    2. webpack会提前打包好main.js,请求时候直接输出打包好的js(先打包再请求)
  4. vite缺点

    1. 热更新常常失效(刷新即可)
    2. rollup生态较webpack还是有一定差距
    3. 兼容性差,不支持非现代浏览器

6 webpack如何配置多页应用

通过chunks与js关联

7 webpack编译过程

  • babel原理

    • 将code解析为AST,遍历AST进行修改(ES5),最后基于新的AST生成code
  • 递归分析js文件的依赖关系

  • 构建流程:

    1. 启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
    2. 从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
    3. 将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
    4. 在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
  • Webpack 的 Tapable 事件流机制保证了插件的有序性,使得整个系统扩展性良好。