z-memo / interview

我们缺的从来都不是前端/后端工程师,而是工程师(或者那些会系统思考,并总是想着解决问题的人)
27 stars 3 forks source link

webpack 中 loader 和 plugin 的区别是什么 #69

Open MrSeaWave opened 3 years ago

MrSeaWave commented 3 years ago

webpack 是一个用于现代JavaScript 应用程序的静态模块打包工具。

loader:loader 是一个转换器,将 A 文件进行编译成 B 文件,属于单纯的文件转换过程;

plugin:plugin 是一个扩展器,它丰富了 webpack 本身,针对是 loader 结束后,webpack 打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听 webpack 打包过程中的某些节点,执行广泛的任务。
MrSeaWave commented 3 years ago

loader:webpack自身只支持js和json这两种格式的文件,对于其他文件需要通过loader将其转换为commonJS规范的文件后,webpack才能解析到 plugin:是用于在webpack打包编译过程里,在对应的事件节点里执行自定义操作,比如资源管理、打包优化、环境变量注入等,目的是解决 loader 无法实现的其他事

image

MrSeaWave commented 3 years ago

loader:让webpack能够处理非js文件(自身职能理解js),然后你就可以利用 webpack 的打包能力,对它们进行处理。 例如:css-loader、style-loader、postcss-loader、sass-loader

plugins:从打包优化和压缩,一直到重新定义环境中的变量. 例如:uglify-webpack-plugin、clean-webpack-plugin、babel-polyfill

常见的plugin & loader
#### 常见的 loader 1. file-loader :文件加载 2. url-loader:文件加载,可以设置阈值,小于时把文件base64编码 3. image-loader:加载并压缩图片 4. json-loader:webpack默认包含了 5. babel-loader:ES6+ 转成ES5 6. ts-loader:将ts转成js 7. awesome-typescript-loader:比上面那个性能好 8. css-loader:处理[@import](https://github.com/import)和url这样的外部资源 9. style-loader:在head创建style标签把样式插入; 10. postcss-loader:扩展css语法,使用postcss各种插件autoprefixer,cssnext,cssnano 11. eslint-loader,tslint-loader:通过这两种检查代码,tslint不再维护,用的eslint 12. vue-loader:加载vue单文件组件 13. i18n-loader:国际化 14. cache-loader:性能开销大的loader前添加,将结果缓存到磁盘; 15. svg-inline-loader:压缩后的svg注入代码; 16. source-map-loader:加载source Map文件,方便调试; 17. expose-loader:暴露对象为全局变量 18. imports-loader、exports-loader等可以向模块注入变量或者提供导出模块功能 19. raw-loader可以将文件已字符串的形式返回 20. 校验测试:mocha-loader、jshint-loader 、eslint-loader等 #### 常见plugin - ignore-plugin:忽略文件 - uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前使用) - terser-webpack-plugin: 支持压缩 ES6 (Webpack4) - webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度 - mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 - serviceworker-webpack-plugin:为网页应用增加离线缓存功能 - clean-webpack-plugin: 目录清理 - speed-measure-webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时 - webpack内置UglifyJsPlugin,压缩和混淆代码。 - webpack内置CommonsChunkPlugin,提高打包效率,将第三方库和业务代码分开打包。 - ProvidePlugin:自动加载模块,代替require和import - html-webpack-plugin可以根据模板自动生成html代码,并自动引用css和js文件 - extract-text-webpack-plugin 将js文件中引用的样式单独抽离成css文件 - DefinePlugin 编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用。 - HotModuleReplacementPlugin 热更新 - DllPlugin和DllReferencePlugin相互配合,前者第三方包的构建,只构建业务代码,同时能解决Externals多次引用问题。DllReferencePlugin引用DllPlugin配置生成的manifest.json文件,manifest.json包含了依 赖模块和module id的映射关系 - optimize-css-assets-webpack-plugin 不同组件中重复的css可以快速去重 - webpack-bundle-analyzer 一个webpack的bundle文件分析工具,将bundle文件以可交互缩放的treemap的形式展示。 - compression-webpack-plugin 生产环境可采用gzip压缩JS和CSS - happypack:通过多进程模型,来加速代码构建
MrSeaWave commented 3 years ago

通俗点讲loader是转换,plugin是执行比转换更复杂的任务,比如合并压缩等

MrSeaWave commented 3 years ago

webpack plugins的执行时机?

加载文件完成后,输出文件前,不同的plugins有不同的执行时机。

MrSeaWave commented 2 years ago

一个最简单的loader例子:

Loader 本身仅仅只是一个函数,接收模块代码的内容,然后返回代码内容转化后的结果,并且一个文件还可以链式的经过多个loader转化(比如scss-loader => css-loader => style-loader)。

一个 Loader 的职责是单一的,只需要完成一种转化。 如果一个源文件需要经历多步转化才能正常使用,就通过多个 Loader 去转化。 在调用多个 Loader 去转化一个文件时,每个 Loader 会链式的顺序执行, 第一个 Loader 将会拿到需处理的原内容,上一个 Loader 处理后的结果会传给下一个接着处理,最后的 Loader 将处理后的最终结果返回给 Webpack。

module.exports = function(source) {
  // source 为 compiler 传递给 Loader 的一个文件的原内容
  // 该函数需要返回处理后的内容,这里简单起见,直接把原内容返回了,相当于该 Loader 没有做任何转换
  return source;
};

一个最简单的plugin例子:

plugin 的实现可以是一个类,使用时传入相关配置来创建一个实例,然后放到配置的 plugins 字段中,而 plugin 实例中最重要的方法是 apply,该方法在 webpack compiler 安装插件时会被调用一次,apply 接收 webpack compiler 对象实例的引用,你可以在 compiler 对象实例上注册各种事件钩子函数,来影响 webpack 的所有构建流程,以便完成更多其他的构建任务。

class BasicPlugin{
  // 在构造函数中获取用户给该插件传入的配置
  constructor(options){
  }

  // Webpack 会调用 BasicPlugin 实例的 apply 方法给插件实例传入 compiler 对象
  apply(compiler){
    compiler.plugin('compilation',function(compilation) {
    })
  }
}

// 导出 Plugin
module.exports = BasicPlugin;

Webpack 启动后,在读取配置的过程中会先执行 new BasicPlugi(options) 初始化一个 BasicPlugin 获得其实例。 在初始化 compiler 对象后,再调用 basicPlugin.apply(compiler) 给插件实例传入 compiler 对象。 插件实例在获取到 compiler 对象后,就可以通过 compiler.plugin(事件名称, 回调函数) 监听到 Webpack 广播出来的事件。 并且可以通过 compiler 对象去操作 Webpack。

开发 Plugin 最主要的就是理解 compiler 和 compilation,它们是Plugin 和 Webpack 之间的桥梁。这两者提供的各种 hooks 和 api,则是开发plugin 所必不可少的材料,通过 compiler 和 compilation 的生命周期 hooks,也可以更好地深入了解 webpack 的整个构建工作是如何进行的。