webpack的长处

webpack从配置的入口登程,能够打包所有前端资源,同时能够配置多种loader来解决不同类型文件的转换,并且能够配置plugin来扩大模块打包流程,满足更多构建中非凡的需要,开发过程中还能够应用HMR晋升本地开发效率和体验,生产环境中能够利用代码压缩和代码宰割来晋升前端加载性能,总之就是既能够晋升开发效率,又能够晋升利用性能。

webpack中loader和plugin的区别

webpack中loader次要用于解决非JavaScript模块的转换,在固定的阶段中应用,自身只是一个函数,返回转换后的后果,因为webpack只能解决js;而plugin是用于解决非凡的构建需要,比方将css代码独自输入为一个文件、定义环境中的变量等,利用了webpack的hooks染指构建过程中不同的阶段,能够定制我的项目的构建流程。

开始编译,读取webpack配置,创立NormalModuleFactory,创立NormalModule(应用resolveLoader解析loader门路),开始编译模块(loader-runner)

如何利用webpack晋升利用性能

webpack优化性能大略有三种形式:
代码压缩、代码宰割、去除无用代码,次要的方向是缩小申请体积,代码宰割有的状况下还能够利用浏览器缓存,缩小申请次数

  1. 代码压缩(次要就缩小申请体积)
    咱们能够对optimization下的minimize和minimizer配置项进行设置,配置TerserPlugin对js代码进行压缩解决,还能够应用插件如HTMLWebpackPlugin对html文件进行压缩。
  2. 代码宰割(既缩小一次的申请体积,使申请返回更快,有的状况还能够利用浏览器缓存,缩小申请次数)
    我理解的大略几种形式,第一种是设置optimization下的splitChunks配置项、第二种css代码利用MiniCssExtractPlugin插件独自生成文件、第三是利用webpack的dllPlugin插件将第三方库打包成独立的文件。
    splitChunks能够将模块抽离为独自的文件,chunks能够设置为all/async/inital三个值的其中一个,all就是所有的模块都打包到一个chunk,async是把异步加载的模块打包到chunk中,如通过动静import加载的模块,initial是把同步加载的模块打包到chunk中。能够配合按需加载应用,按需加载应用ES动静加载语法import来加载模块,webpack会主动解决应用这种语法编写的模块,把模块独自拆散成文件,能够缩小大型利用初始化时须要加载的前端资源,晋升用户体验。
    css代码利用plugin插件生成独自的文件,能够在后续申请中,利用浏览器缓存,如果是多页面利用,长处更显著,不必屡次加载css。
    dllPlugin也是将局部模块抽离成独自的文件,然而它和splitChunks不同,在代码不变的状况下不必反复打包,能够独自写一个配置文件,运行打包,在后续我的项目的构建流程间接应用DLLReferencePlugin援用文件就能够,通常能够用来解决不太变动的第三方库,能够看进去这样不仅能够利用浏览器缓存,还能进步开发效率。
  3. 去除无用代码(缩小申请体积)
    能够利用tree-shaking、还有sideEffects,将未应用的代码移除。
    要利用到tree-shaking就要应用别离导入、而不是整体导入,未引入和未应用的模块办法就不会被打包,sideEffects对没有副作用的模块也能够将模块中未应用到的代码不进行打包。
    还有webpack的IgnorePlugin插件,能够在打包中疏忽掉某些依赖包中体积大但又不太须要的文件,如react脚手架生成的我的项目中就默认将moment的locale文件夹整个疏忽掉,这个语言包会十分大,然而通常理论中不须要这些多语言的配置,独自引入须要的语言就能够。

webpack的热更新原理

热更新HMR就是不必刷新页面而将新变更的模块替换掉旧的模块,防止了频繁手动刷新页面、利用状态失落,也缩小了页面刷新时的期待。它的外围是客户端去服务端拉取更新后的文件。在DevServer开启hot后,webpack会往利用代码中增加websocket相干的代码,用于和服务器放弃连贯,期待更新动作,本地代码变更时告诉浏览器做相应的解决;webpack还会往利用代码中增加HMR运行时的代码,用于定义利用更新时的API。当有更新时,webpack-dev-server发送更新信号给HMR运行时,而后HMR再申请所须要的更新数据,服务端返回一个json蕴含所有要更新的模块的hash值,对应模块再次申请获取到最新的模块代码,没有问题的话就进行利用更新。

利用更新的API常见的有module.hot.accept、module.hot.decline、module.hot.dispose等,accept是在利用特定代码模块更新时执行相应的callback;decline是对于指定的代码模块,回绝进行更新;dispose用于增加一个处理函数,在模块代码被替换时运行(可用于移除之前增加的长久化资源或者相干状态)。

如何优化webpack的构建速度

总的来说方向就是缩小webpack的工作量。

  • 首先在开发环境下应用配置mode为develpment,webpack自身就默认不配置一些压缩优化的插件,这样能够缩小在优化操作上的工夫耗费;
  • 其次提前解决一些文件资源,如应用imagemin或者其余工具提前压缩好图片,能够缩小在图片解决上的耗时,一些不频繁更新的第三方库应用dllPlugin打包,在我的项目中间接援用,不打包到利用代码中,也能够大大减少构建所用工夫;
  • 还能够通过配置resolve,设置适宜的extensions、modules、mainFields、mainFiles的值,缩小模块解析时门路的查问范畴,配置module的rules应用loader解决不同的文件时,通过include和exclude限度解决范畴,缩小耗时;
  • 另外还能够应用thread-loader利用多过程减速loader执行,利用tree-shaking缩小webpack解决打包的代码量,利用缓存晋升二次构建速度,像babel-loader、terser-webpack-plugin都能够开启缓存。
  • 生产环境还能够配置devtool不输入sourcemap。
  • 如果我的项目十分大,波及代码模块过多,在适合的状况下也能够依据肯定的粒度,把不同的业务代码拆分到不同的代码库去保护和治理,缩小webpack解决的代码量。

如何开发一个webpack的plugin

plugin的实现能够是一个类或者函数,应用时传入相干配置来创立一个实例,plugin实例最重要的办法就是apply,在webpack compiler装置插件时会被调用,接管webpack的compiler对象实例的援用作为参数,在compiler对象实例上咱们能够注册各种事件钩子函数hooks,在compiler的有些hooks中,还能够获取到compilation对象实例,在compilation对象实例上注册各种hooks,咱们能够通过注册各种hooks来影响webpack的所有构建流程,以便实现更多其余构建工作。

hooks能够简略分为同步和异步两种,同步类型的hooks只能应用tap来注册事件,异步的还能够应用tapPromise和tapAsync来注册。

本地开发plugin,能够使自定义plugin对外裸露一个类,而后在webpack配置文件中引入,运行webpack构建查看后果就能够,能够应用node命令进行调试。

compiler一些hooks:entryOption、beforeRun、emit、compilation、thisCompilation、make(compilation实现编译后执行)、shouldEmit(管制是否输入对应的构建后果)、assetEmitted(在构建后果输入之后执行,能够获取输入内容的相干信息)、done、failed(构建失败时执行)

compilation一些hooks:buildModule、finishModules、chunkAsset(chunk 对应的一个输入资源增加到compilation时执行)、processAssets

如何开发一个webpack的loader

webpack loader实质就是一个实现转换性能的函数,接管content、map、meta三个参数。content就是要进行转化的资源内容,能够是字符串或者buffer,如图片、字体等文件,map是sourcemap对象。

通常webpack loader都是基于一个实现外围性能的类库来开发的,如果间接return一个值,这个值就是转换后的内容,如果要返回sourcemap对象或者其余数据,或是抛出一个异样,须要应用this.callback(err, content, map, meta)来传递这些数据;有些loader在执行过程中可能依赖内部I/O的后果,就须要应用异步的形式来解决,在loader执行时调用this.async()来标识该loader是异步解决的,this.async()会返回一个函数,而后咱们能够调用这个函数用于返回loader的处理结果。

应用本地开发的loader有两种形式:一种是配置loader时应用本地的门路;另一种是在loader门路解析中退出本地开发loader的目录,具体是在loader所在目录下增加package.json文件并配置name字段,而后配置resolveLoader的modules将loader所在目录的门路增加进去,并在配置loader时应用package.json中name的值,这种比拟适宜多个loader的状况。

官网提供的一个工具库loader-utils能够帮忙咱们获取给loader传递的options,咱们还能够应用官网提供的schema-utils对传入的options进行校验。