Open chiwent opened 5 years ago
在工程中如果代码混用了这两种规范,可能就遇到构建失败的情况。实际上,这样的方式也是不提倡的。可以参考下面的讨论:
https://github.com/webpack/webpack/issues/4039#issuecomment-281136701
事实上,webpack内部就维护了包管理工具,支持ES Module、Commonjs、AMD 模块化规范。
如果需要处理这样的冲突问题,可以对babel的配置文件进行修改,将modules
的配置选项设置为commonjs
(js最终编译得到CommonJS规范)或者umd
(js最终编译得到umd规范)以支持这两种模块规范的混用。
重学webpack
在开始接触前端工程化的时候,第一个上手的工具就是webpack。最开始使用webpack,只是用在
html+css+js
的场景下进行打包配置。在这种场景下,项目工程的复杂度较低,基本上参照着webpack官网,配置好相关参数就可以跑通项目了。后来接触vue后,开始使用vue-cli脚手架简单搭建主体项目环境,也就只是稍微改动一些插件、loader以及其他配置。但是在接触到vue ssr后,逐渐意识到在webpack配置对前端开发的重要性,所以也就有了这篇笔记,重学webpack。1 初始化项目
1.1 安装依赖
首先初始化项目:
在执行完
npm init
后,项目目录下会多出一个package.json
的文件,在这里可以看得到项目下安装的webpack插件,也修改npm命令。补充说明:
在
npm install
安装相关工具时,如果使用了--save
,依赖会添加到package.json
中的dependencies
选项中;如果使用了--save-dev
,依赖会添加到package.json
中的devDependencies
中,注意区分。在上述提到的插件中,
webpack-dev-server
可以提供一个简单的本地服务,并且具有热重载的功能。1.2 编辑配置
在项目路径下,新建一个名为
webpack.config.js
的配置文件,基本结构如下:简要说明一下该配置文件的内容:
其中,开发环境推荐使用
cheap-module-eval-source-map
,生产环境推荐:cheap-module-source-map
(这也是下版本 webpack 使用-d命令启动debug模式时的默认选项)其他的具体配置参数可以参考:webpack官方文档 - devtool以及深入浅出的webpack构建工具---devTool中SourceMap模式详解(四)
./src/index.js
打包为./dist/bundle.js
。其中,这里有几个关键的path
变量信息,可参考:webpack中的path、publicPath和contentBase具体可参考:外部扩展(externals)
另外补充一点,如果需要全局使用jQuery,那么可以在webpack公共配置文件(webpack.base.conf.js)中设置,其中
ProvidePlugin
提供和暴露全局变量:假如我们要单独打包类似jQuery这样的类库,可以在公共配置中加上设置如下:
另外的一些概念:
关于webpack配置中的process.env
在node当中,process表示的是当前node的进程,process.env就包括了系统环境信息,但是process.env不包括NODE_ENV这个属性,她是用户自定义的变量,用来判断当前环境。
而我们在
package.json
配置中就有关于环境变量NODE_ENV的配置(当然你放在其他文件下也没问题),如:这样,我们就将NODE_ENV绑定到了process.env上,并且按以上配置,我们只能在webpack.dev.conf.js中以及它所引入的脚本中访问到process.env.NODE_ENV,其他地方都不可访问到。
2 构建流程
webpack的构建流程是串行的,如下:
package.json
读取对应的命令配置,得出最终参数Compiler
,加载所有plugin,执行对象的run方法并开始编译。接着根据配置中的entry找到所有入口文件流程图可以参考这里:https://juejin.im/post/5c6b78cdf265da2da15db125
webpack打包的规则是,一个入口文件对应一个bundle,该bundle包括了入口文件模块和其他依赖模块,按需加载的模块或者需要单独加载的模块则是分开打包生成其他的bundle。在这些bundle中,有一个较为特殊,就是manifest.bundle.js,被称作webpackBootstrap,它是最先加载的,负责解析webpack生成的其他bundle。
3.具体配置
3.1 loader
3.1.1 babel
安装:
babel是JavaScript的转码器,可以现代js脚本内容转换为ES5、ES3。下面介绍几个常用的babel loader:
补充说明babel-stage-x对应的ECMA标准:
可以参考:What's the difference between babel-preset-stage-0, babel-preset-stage-1 etc?
在webpack配置对应的babel loader时,也需要在项目下创建
.babelrc
文件,下面举出demo:webpack的配置举例如下:
3.1.2 样式相关的loader
常见的css预处理器有less、sass、stylus等,它们都有对应的loader,以less和css的配置为例:
3.1.3 静态资源相关loader
如果我们要处理一些图片,就很大概率上会接触到file-loader和url-loader,二者有相似之处,二者在处理图片时可以将其打包到dist目录,接着会获取图片模块的地址,并将地址返回到引入模块的变量中。url-loader基本可以实现file-loader的功能,但是在url-loader是将图片转换为base64直接放入bundle.js下,而file-loader会将图片放到dist目录下。
3.2 plugin
3.2.1 常用插件
webpack.base.conf.js
(公共配置)、webpack.dev.conf.js
(开发环境配置)、webpack.prod.conf.js
(生产环境配置)的配置文件。然后再合并webpack配置项,比如合并webpack.base.conf.js
和webpack.dev.conf.js
4 优化
4.1 巧用resolve
可以通过
resolve.modules:[path.resolve(__dirname, 'node_modules')]
来定位第三方模块,默认是node_modules
;设置resolve.alias
来生成一个快速引用符号指向目标目录;在使用loader的时候,可以通过test、exclude、include、正则来缩小搜索范围另外,使用
alias
可以加快webpack查找模块的速度。4.2 抽离公共代码
如果在两个组件中都引用了共同的组件,那么我们可以将公共组件代码抽离出来
最后打包的结果中会生成
index.js
和login.js
或者是:
4.3 使用DllPlugin减少基础模块的编译次数
DllPlugin是动态链接库插件,原理是将网页依赖的基础模块抽离出来打包到dll文件中,当需要导入的模块存在于某个dll文件中,该模块不再被打包,而是通过dll获取。
打包后生成:
4.4 使用IgnorePlugin忽略某些模块打包
IgnorePlugin可以让webpack不打包指定的模块:
4.5 生产环境中将提前构建的包同步到dist
4.6 代码压缩
webpack内置的uglifyjs插件可以实现js代码压缩:
另外,使用
css-loader?minimize
不仅可以删除样式文件的空格,还可以语义化地压缩css代码(rgb转色彩名)4.7 使用静态资源CDN
参考:
4.8 多进程打包
可以使用
HappyPack
这个插件进行webpack的多进程打包,以下放出网上找来的一段相关配置,来自:加速 Webpack,文章内也有具体的配置说明,详情可点击链接访问4.9 runtime和manifest
在webpack项目构建中,有三种基本的代码类型:
在单页应用中,客户端发起网络请求后,从服务端返回的文件主要是入口的html文件和一系列bundle文件,然后交由浏览器解析处理。经由webpack打包过后的项目,在不同的打包策略模式下,代码的执行逻辑是不同的,但是它们都需要通过webpack来进行管理模块间的交互。而runtime和manifest就是指在浏览器运行时,webpack通过连接模块化应用程序的所有代码。runtime包括了在模块交互时,连接模块所需的加载和解析逻辑,包括浏览器中已加载模块的连接、懒加载模块的执行逻辑。
为了更加清晰地理解manifest,我们简要复述一遍webpack的工作流程:
当webpack写入bundle时,它会维护一个manifest,你可以在项目中生成的bundle找到它,它内部描述了webpack应该加载的文件。如果文件的hash值改变,manifest也会改变,然后也跟着一些分离出来的代码共同打包。这显然不是我们想要的,所以我们需要提取出manifest:
4.10 缓存优化
浏览器加载js文件时,如果文件名和浏览器本地缓存一致,那么就不会向后台发送请求。假如我们的业务代码中做了修改,但是webpack打包出来的文件名对应的hash值不变,那么就不会用上新代码。另外,在前端项目中一般是只有业务代码才会频繁变化,而第三方依赖是很少变化的,所以我们希望浏览器不用再重复地向服务端发送请求,这就要求我们进行代码分块打包,将一些第三方依赖集中整合进单个bundle下。所以,我们可以借助webpack.optimize.CommonsChunkPlugin将manifest、第三方依赖、业务代码分别独立打包
4.11 打包分析
可以使用
webpack-bundle-analyzer
对webpack打包结果进行分析,支持可视化的。参考:
扩展阅读: