webpack 相关

 webpackgruntgulp 的区别

grunt、gulp 是基于任务运行的工具:它们会自动执行指定的任务,就像流水线,把资源放上去而后经过不一样插件进行加工,它们包含活跃的社区,丰富的插件,能方便的打造各类工做流。css

webpack 是基于模块化打包的工具:webpack 把一切都当作模块,当 webpack 处理程序时,会递归地构建一个依赖关系图,其中包含应用程序须要的每一个模块,而后将全部的模块打包成一个或者多个 bundlehtml

所以这是两类彻底不一样性质的工具,而 npm script 也能够打造任务流。前端

webpackrollupparcel 优劣

webpack 适用于大型复杂的前端站点构建:webpack 有强大的 loader 和插件生态,打包后的文件实际上就是一个当即执行函数,这个当即执行函数接收一个参数(模块对象),键为各个模块的路径,值为模块内容。当即函数内部处理模块之间的引用、执行模块等,更适合文件依赖复杂的应用开发。vue

rollup 适用于基础库的打包,好比说vued3等。rollup 将各个模块打包进一个文件中,并经过 Tree-shaking 来删除无用的代码,能够最大程度上下降代码体积,可是 rollup 没有 webpack 那么多的代码分割、按需加载等功能,更加适合库的开发。webpack

parcel 适用于简单的实验性项目:能够知足低门槛的快速看到效果,可是生态差、报错信息不够全面都是问题,除了一些实验性项目不建议使用。web

常见的 loader

  • file-loader 把文件输出到一个文件夹中,在代码中经过相对 URL 引用输入的文件
  • url_loader 和 file-loader 相似,能在文件很小的状况下以 base64 的方式将文件内容注入到代码中
  • source-map-loader 加载额外的 Source Map 文件,方便断点调试
  • image-loader 加载并压缩图片文件
  • babel-loader 将 ES6 转换为 ES5
  • css-loader 加载 css,支持模块化、压缩、文件导入等特性
  • style-loader 把 css 代码注入到 JavaScript 中,经过 DOM 操做去加载 css
  • eslint-loader 经过 ESLint 检查 JavaScript 代码
  • html-minify-loader 压缩HTML

loader 特性

  • loader 从右到左地取值(evaluate)/执行(execute)
  • loader 支持链式传递,链中的每一个 loader 会将转换应用在已处理过的资源上
  • loader 也能够内联显示指定
  • loader 能够是同步的,也能够是异步的
  • loader 运行在 Node.js 中,而且可以执行任何 Node.js 能作到的操做
  • loader 能够经过 options 对象配置
  • 除了常见的经过 package.json 的 main 来将一个 npm 模块导出为 loader,还能够在 module.rules 中使用 loader 字段直接引用一个模块
  • loader 可以产生额外的任意文件

常见的 plugin

  • define-plugin 定义环境变量
  • html-webpack-plugin 简化 html 文件建立
  • uglifyjs-webpack-plugin 经过 UglifyES 压缩 ES6 代码
  • webpack-parallel-uglify-plugin 多核压缩,提升压缩速度
  • webpack-bundle-analyzer 可视化 webpack 输出文件的体积
  • mini-css-extract-plugin CSS 提取到单独的文件中,支持按需加载
  • clean-webpack-plugin 在每次构建前清理 /dist 文件夹

loaderplugin 的不一样

做用不一样

loader 为加载器,webpack 将一切文件视为模块,可是 webpack 原生只能解析 js 和 json 文件,若是想将其余文件也打包的话,就会用到 loader,所以,loader 的做用是让 webpack 能够加载和解析非 JavaScript 文件。npm

plugin 为插件。能够扩展 webpack 的功能,让 webpack 更灵活。在 webpack 的运行周期中会广播出许多事件,plugin 能够监听这些事件,在合适的时机经过 webpack 提供的 API 改变输出结果。json

用法不一样

loader 在 module.rules 中配置,即做为模块的解析规则存在。类型为数组,每一项都是一个 object,里面描述了对于什么类型的文件是用什么加载和使用的参数。gulp

plugin 在 plugins 中单独配置。类型为数组,每一项是一个 plugin 的实例,参数都是经过构造函数传入。数组

bundlechunkmodule

bundle webpack 打包出来的文件

chunk 代码块,一个 chunk 由多个模块组合而成,用于代码的合并和分割

module 开发中的单个模块,webpack 中一切皆模块,一个模块对应一个文件

webpack 的构建流程

webpack 的运行流程是一个串行的过程,从启动到结束会一次执行如下流程:

  1. 初始化参数:从配置文件和脚本语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步获得的参数初始化 Compiler 对象,加载全部配置的插件,执行对象的 run 方法开始执行编译;
  3. 肯定入口:根据配置中的 entry 找出全部的入口文件;
  4. 编译模块:从入口文件出发,调用全部配置的 loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤,直到全部入口文件依赖的文件都通过了本步骤的处理;
  5. 完成模块编译:第4步翻译完成全部模块后,获得了每一个模块被翻译后的最终内容以及它们的依赖关系;
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 chunk,再把每一个 chunk 转换成一个单独的文件加入到输出列表,这步是能够修改输出内容的最后机会;
  7. 输出完成:在肯定好输出内容后,根据配置肯定输出的路径和文件名,将文件内容写入到文件系统。

在以上过程当中,webpack 会在特定的时间点广播出特定的时间,插件在监听到事件后,会执行特定的逻辑,而且插件能够调用 webpack 提供的 API 改变 webpack 的运行结果。

是否本身写过 loaderplugin

loader 把读到的源文件内容转义成新的文件内容,而且每一个 loader 经过链式操做,将源文件转换成想要的样子。

编写 loader 的时候要遵循单一原则,每个 loader 只作一种转义工做,loader 拿到的是源文件内容(source),处理后能够经过返回值的方式将处理后的内容输出,也能够调用 this.callback() 方法将内容返回给 webpack。还能够经过 this.async() 生成一个 callback 函数,再用这个 callback 将处理后的内容输出出去。此外 webpack 还为开发者准备了开发 loader 的工具函数集 —— loader-utils

plugin 监听 webpack 运行中广播出的事件,在合适的时机经过 webpack 提供的 API 改变输出结果。

webpack 的热更新是如何作到的

热更新又称做热替换(Hot Module Replacement),缩写为 HMR。这个机制能够作到不用刷新浏览器而将新变动的模块替换掉旧的模块。

热更新在 server 端和 client 端都作了处理

  1. webpackwatch 模式下,文件系统中的某个文件发生改变,webpack 监听到文件变化,根据配置文件对模块从新编译打包,并将打包后的代码经过简单的 JavaScript 对象保存在内存中。
  2. webpack-dev-serverwebpack 之间的接口交互,这一步,主要是 dev-server 的中间件 webpack-dev-middlewarewebpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API 对代码变化进行监控,而且告诉 webpack 将代码打包到内存中。
  3. webpack-dev-server 对文件变化的监控,并非监控代码变化从新打包。当在配置文件中配置了 devServer.watchContentBasetrue 的时候,server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload,这里是浏览器刷新。
  4. wecpack-dev-server 代码的工做,主要经过 sockjswebpack-dev-server 的依赖)在浏览器端和服务器端创建一个 websocket 的长链接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第3步中 server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不一样的操做,服务端传递的主要信息仍是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
  5. webpack-dev-server/client 端并不可以请求更新代码,也不会执行热更新模块操做,这些工做依旧会交回给 webpackwebpack/hot/dev-server 的工做是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器仍是进行模块热更新。若仅仅是刷新浏览器,就没有后续的操做了。
  6. HotModuleReplacement.runtime 是客户端 HMR 的中枢,接收上一步传给它的新模块的 hash 值,经过 JsonpMainTemplate.runtimeserver 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了全部要更新的模块的 hash 值,获取到更新列表后,该模块再次经过 jsonp 请求获取到最新的模块代码。
  7. HotModulePlugin 会对新旧模块进行对比,决定是否更新模块,再决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
  8. HMR 失败后,回退到 live reload 操做,也就是进行浏览器刷新来获取最新打包代码。

webpack 优化前端性能

  • 压缩代码:删除多余的代码、注释、简化代码的写法。可使用 UglifyJsPluginParallelUglifyPlugin 来压缩 JS 文件,利用 cssnano 来压缩 css 代码。
  • 利用 CDN 加速:在构建的过程当中将引用的静态资源路径修改成 CDN 上对应的路径,可使用 webpack 对于 output 参数和各个 loader 的 publicPath 参数来修改资源路径。
  • Tree Shaking:将代码中永远不会走到的片断删除掉,能够在启动 webpack 时追加参数  --optimize-minimize 来实现。
  • Code Splitting:将代码按照路由维度或者组件分块,能够作到按需加载,同时能够充分利用浏览器缓存。
  • 提取公共第三方库:SplitChunksPlugin 插件来进行公共模块抽取,利用浏览器缓存能够长期缓存这些无需频繁变更的公共代码。

提升 webpack 的打包速度

  • happypack:利用进程并行编译 loader,利用缓存来使得 rebuild 更快,相似的替代者:thread-loader
  • 外部扩展:将不怎么须要的第三方库脱离 webpack 打包,减小打包时间。
  • dll:采用 webpackDllPluginDllReferencePlugin 引入 dll,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。
  • 利用缓存:webpack.cachebabel-loader.cacheDirectoryHappyPack.cache 均可以利用缓存提升 rebuild 的时间。
  • 缩小文件搜索范围:好比 babel-loader,若文件仅存在于 src 中可使用:include: path.resolve(__dirname, src)

提升 webpack 的构建速度

  • 多入口状况下,使用 CommonsChunkPlugin 来提取公共代码
  • 经过 external 配置来提取经常使用库
  • 利用 DllPluginDllReferencePlugin 预编译资源模块,经过 DllPlugin 来对哪些引用可是绝对不会修改的 npm 包来进行预编译,再经过 DllReferencePlugin 将预编译的模块加再加载进来
  • 使用 HappyPack 实现多线程加速编译
  • 使用 webpack-uglify-parallel 来提高 uglifyPlugin 的压缩速度
  • 使用 Tree-shakingScope Hoisting 来剔除多余代码
相关文章
相关标签/搜索