(本文章还在持续更新中。。。。)
使用webpack做构建也有一段时间了,记录一下使用webpack的心得。
我们来看看官网对webpack的描述。
webpack is a module bundler for modern JavaScript applications. When webpack processes your application, it recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles - often only one - to be loaded by the browser.
It is incredibly configurable, but to get started you only need to understand Four Core Concepts: entry, output, loaders, and plugins.
This document is intended to give a high-level overview of these concepts, while providing links to detailed concept specific use-cases.
简单来说,webpack是一个现代js应用的模块管理器。他能正确处理模块的依赖方式,并且把多个模块打包成浏览器识别的小数量文件(通常来说只有一个文件,但是如果采用异步加载或者代码拆包的化就有多个了),webpack是基于配置式的,最核心的四个参数是入口、出口、模块加载器和插件。
入口、出口都好理解,我这里要补充一下output的publicPath参数。默认为/,它是主文件加载其他文件时的路径前缀。比如你构建时产生了多个js文件,主文件是app.js。app.js加载其他文件时,会在路径前面补全publicPath。
loaders是用于处理不同的文件。因为webpack是基于nodejs的,而nodejs默认只能识别js文件,所以less、json等文件需要相应的loader来将文件转换成js。loaders具有如下特点:
- 支持链式调用,有先后顺序,前一个loader的返回作为下一个loader的输入
- 最终要生成js
常用的loader总结如下: - file-loader用于生成md5命名的文件
- url-loader 将文章转换成dataurl的方式
- css-loader加载css文件。可以解析里面的import,css模块化。soucemap等
- style-loader将js化的css包裹style标签,并嵌入到html中,一般配合css-loader使用
-
ts-loader解析typescript
...
plugin
如果说loader是对具体资源类型上对资源文件的转换扩展。那么plugin则相当于在全局上做扩展。官方推荐plugin插件一览表
如果有多个chunk共享相同的依赖,我们可以用CommonsChunkPlugin来提取相同的依赖性到当独的文件
resolve
这个配置很实用。在处理模块依赖关系的时候,涉及到嵌套比较深的文件,我们很可能会写出这样的代码
import Utility from '../../utilities/utility';
通过resolve.alias就可以设置一个别名,正确的让webpack从该路径中查找
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/')
}
通过resolve.modules可以指定node_modules的查找路径,适用于一个大项目嵌套多个小项目的情况,可以让小项目共享相同的node_modules,但是如果是同一个包的不同版本,则不可用。
webpack的Code Splitting async
当你的代码打包后仍很大的时候,你就要考虑进行代码拆包了。把一些没有必要立刻加载的代码拆包,并异步去加载。在webpack中,你可以通过import()和require.ensure来实现
import是es6的一个特性,在webpack中。webpack会把import()命令识别成代码切割的点(记住,import后面有括号包裹,包裹的为要加载的模块路径),而且webpack的import异步加载模块是基于promise,这意味着低版本浏览器你需要加promise的polyfill。
而且import()需要你正确处理依赖项,因为webpack只是单纯的将模块当独拆包。如果需要处理依赖关系的化,还是使用require.ensure比较合适。
webpck打包项目中包括第三方库
在webpack打包中,经常会遇到引用第三方库的情况,这时候你可以将代码打包成三块(不包括拆包生成的小chunk)
1.webpack的模块引入代码。主要是webpackJsonp的实现和共同的代码块。
2.第三方库
3.主要的业务代码
要实现上述的三种分离。需要用到CommonsChunkPlugin来分离多次引用的chunk。用DllReferencePlugin和DllPlugin来分离第三方应用。
不过不建议通过这种方式打包第三方依赖库,还是直接使用第三方库提供的dist版本吧,直接打包生成的可能是开发中版本而不是release版本。
externals的使用场景
如果在wepack中定义了externals,webpack会在import、require的时候忽略对应模块,并externals中对应模块的值赋给模块。也就是说,该模块不会被打包进去最终的代码。比如你externals设置了
并在代码中对jquery进行了引用
import jquery from "jquery"
webpack在打包的时候会在externals中匹配到jquery,从而只是简单的进行变量替换
要注意的
webpack使用场景
1.处理代码依赖。当你项目复杂,需要引入许多静态资源,而且静态资源有依赖关系,优先关系时
2.代码的并包(多个静态资源合并,在进行模块化开发一定会用到)
3.代码的拆包(当你的资源需要多个页面复用而需要把共同的代码分离,以便用于浏览器缓存时。)
4.代码构建,需要区分不同的生成环境时。(比如最常见的三层环境。开发环境、测试环境、线上环境。你可以在开发环境搭建hmr来提高编译效率,在测试环境使用soucemap来方便测试debug,在线上环境压缩混淆版本管理来减小带宽消耗和利用缓存)
webpack调用方式
1.通过cli的方式(在终端中使用webpack命令,适合单独文件需要简单处理的时候使用)
2.通过nodejs 的api方式 (适合多环境搭建的时候使用,比如区分开发环境、测试环境、线上环境等,如何区别?在cli中不同的命令指向不同的配置文件,不同的配置文件用define-plugin定义环境变量,在代码中就可以直接使用这个变量了)