-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
「前端」看懂前端脚手架你需要这篇webpack #7
Comments
要是能解释下什么是“运行时”就更好了 |
|
能不能这么理解,如果配置好的话,webpack加载的顺序是 之后(code splittting的ajax加载)=> |
写得非常好 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
分割webpack配置文件的多种方法
(一)
将你的配置信息写到多个分散的文件中去,然后在执行webpack的时候利用
--config
参数指定要加载的配置文件,配置文件利用moduleimports
导出。你可以在webpack/react-starter 看到是使用这种发方法的。(二)
调用第三方的webpack工具,使用其集成的api,方便进行webpack配置。HenrikJoreteg/hjs-webpack 这个repo就是这么做的。
(三) Scalable webpack configurations
在单个配置文件中维护配置,但是区分好条件分支。调用不同的npm命令时候设置不同的环境变量,然后在分支中匹配,返回我们需要的配置文件。
这样做的好处可以在一个文件中管理不同npm操作的逻辑,并且可以共用相同的配置。webpack-merge这个模块可以起到合并配置的作用。
开发环境下的自动刷新
webpack-dev-server
webpack-dev-server
在webpack的watch
基础上开启服务器。webpack-dev-server
是运行在内存中的开发服务器,支持高级webpack特性hot module replacement
。这对于react vue这种组件化开发是很方便的。使用webpack-dev-server命令开启服务器,配合HMR及可以实现代码更改浏览器局部刷新的能力。
hot module replacement
hmr机制适用于单页应用。
要实现hmr机制,需要配合
webpack-dev-server
服务器,这个服务器本身就实现了监察watch
文件改动的能力,再开启HMR选项,就添加了watch模块变化的能力。这是HMR机制能生效的基础。从webpack编译器角度
每次修改一个模块的时候,webpack会生成两部分,一个是
manifest.json
,另一部分是关于这次模块更新编译完成的chunks。manifest.json中存着的是chunk更改前后的hash值。从编译器webpack的角度来讲提供了hmr的原材料。供后续使用。
从模块的角度
模块发生变化时,webpack会生成之前讲过的两部分基础文件,但是何时将变化后的模块应用到app中去?这里就需要在应用代码中编写handler去接受到模块变化信息。但是不能在所有模块中编写handler吧?这里就用到了消息冒泡机制。
如图A.js、C.js没有相关hmr代码,B.js有相关hmr代码,如果c模块发生了变化,c模块没有hmr,那么就会冒泡到a、b模块。b模块捕捉到了消息,hmr运行时会相应的执行一些操作,而a.js捕捉不到信息,会冒泡到entry.js,而一旦有消息冒泡的入口块,这就代表本次hmr失败了,hmr会降级进行整个页面的reload。
从HMR运行时的角度
HMR运行时是一些相关的操作api,运行时支持两个方法:
check
、apply
。check
发起 HTTP 请求去获取更新的 manifest,以及一些更新过后的chunk。环境变量的设置
注意这里单引号间多了个双引号 why?
以及webpack.DefinePlugin插件的原理?
开发的时候会想写很多只在开发环境出现的代码,比如接口mock等,在build命令后这些代码不会存在。
这对框架或者插件、组件的开发是很有帮助的。vue,react等都会这么做。可以在这些框架的dev模式提供很多有用的提示信息。
打包文件分割
为何要进行打包文件分割?
对于一个单页应用项目来说,有分为业务代码和第三方代码,业务代码会频繁改动,而第三方代码一般来讲变动的次数较少,如果每次修改业务代码都需要用户将整个js文件都重新下载一遍,对于加载性能来讲是不可取的,所以一般而言我们会将代码分为业务代码和第三方代码分别进行打包,虽然多了一个请求的文件,增加了一些网络开销,但是相比于浏览器能将文件进行缓存而言,这些开销是微不足道的。
我们在entry中定义了
app
入口,相应的业务逻辑都封装在这个入口文件里,如果我们想要第三方代码独立出来,就要再增加一个入口,我们习惯使用vendor
这个命名。vendor入口的传参是以一个数组的形式传递的,这是一种非常方便的注入多个依赖的方式,并且能把多个依赖一起打包到一个chunk中。而且不用手动的创建真实存在的入口文件。
这相当于:
但是这样做只是声明了一个
vendor
入口而已,对于app这个入口来说,打包完成的文件还是会有vue和vuex依赖,而新增的入口vendor
打包完成的文件也有了vue和vuex两个依赖。模块依赖关系如下图所示。这里的A可以代表
vue
依赖,最后生成的打包文件是两个平行关系的文件,且都包含vue的依赖。此时需要引入
CommonsChunkPlugin
插件这是个相当复杂的插件,他的基础功能是允许我们从不同的打包文件中抽离出相同的模块,然后将这些模块加到公共打包文件中。如果公共打包文件不存在,则新增一个。同时这个插件也会将运行时(runtime)转移到公共chunk打包文件中。
这里的name可以选择已经存在的块,这里就选择了vendor块,因为我们本来就是将vendor块当做管理第三方代码的入口的。
而names传入一个数组,数组里包含两个trunk name,表示
CommonsChunkPlugin
插件会执行两次这个方法,第一次将公共的第三方代码抽离移到vendor的块中,这个过程之前也讲过会将运行时runtime也转移到vendor块中,第二次执行则是将运行时runtime抽离出来转移到manifest块中。这步操作解决了缓存问题。这样处理,最后会生成3个打包文件chunk,app.js是业务代码,vendor则是公共的第三方代码,manifest.js则是运行时。
chunk type 块的类型大揭秘
webpack1.0官网介绍中的chunk类型读起来及其拗口chunk type, 所以我这里解读一下。
chunk
是webpack中最基本的概念之一,且chunk
常常会和entry
弄混淆。在「打包文件分割部分」我们定义了两个入口entry point -- app和vendor,而通过一些配置,webpack会生成最后的一些打包文件,在这个例子中最后生成的文件有app.js 、 vendor.js 、 manifest.js
。这些文件便被称为块chunk
。entry & chunk 可以简单的理解为一个入口、一个出口
在官方1.0文档中webpack的chunk类型分为三种:
entry chunk 入口块
entry chunk 入口块
不能由字面意思理解为由入口文件编译得到的文件,由官网介绍可以理解为包含runtime运行时的块可以称为entry chunk,一旦原本存在运行时(runtime)的
entry chunk
失去了运行时,这个块就会转而变成initial chunk
。normal chunk 普通块
普通块不包含运行时runtime,只包含一系列模块。但是在应用运行时,普通块可以动态的进行加载。通常会以jsonp的包装方式进行加载。而
code splitting
主要使用的就是普通块。initial chunk 初始块
官方对initial chunk的定义非常简单,初始块就是普通块,跟普通块相同的是同样不包含运行时runtime,不同的是初始块是计算在初始加载过程时间内的。在介绍入口块entry chunk的时候也介绍过,一旦入口块失去了运行时,就会变成初始块。这个转变经常由
CommonsChunkPlugin
插件实现。例子解释
还是拿「打包文件分割」的代码做例子,
没有使用
CommonsChunkPlugin
插件之前,两个entry分别被打包成两个chunk,而这两个chunk每个都包含了运行时,此时被称为entry chunk
入口块。而一旦使用了
CommonsChunkPlugin
插件,运行时runtime最终被转移到了manifest.js
文件,此时最终打包生成的三个chunkapp.js 、 vendor.js 、 manifest.js
,app.js、vendor.js失去了runtime就由入口块变成初始块。code splitting
前文有讲到将依赖分割开来有助于浏览器缓存,提高用户加载速度,但是当业务复杂度增加,代码量大始终是一个问题。这时候就需要
normal chunk
普通块的动态加载能力了。我们需要在业务逻辑中手动添加一些分割点,标明此处事件逻辑之后进行代码块的异步加载。
这段代码表明当用户点击时,异步请求一个js文件,这个文件中包含该有
vue vuex
的依赖。打包后会根据手动分割点的信息生成一个打包文件,就是图中第一行
0
开头的文件。这个文件也就是异步加载的文件。下面是之前的一个vue项目,采用
code splitting
将几个路由抽离出来异步加载之后,文件由212kb减少到了137kb,同样样式文件也由58kb减少到了7kb。对于首屏渲染来说,性能是会增加不少的。有需要交流的可以联系我微博达达的暹罗猫
参考:
The text was updated successfully, but these errors were encountered: