We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
构建工具有很多,比如Npm Script任务执行者、Grunt也是任务执行者、Gulp基于流的自动化构建工具、Fis3百度构建工具、Webpack打包模块化JavaScript工具和Rollup模块打包工具。
JavaScript
这里谈谈用得很频繁的webpack构建工具。
webpack
从最基本的概念开始了解:
entry是配置模块的入口,必填。
entry
module.exports = { entry: './path/to/my/entry/file.js' }
output配置如何输出最终想要的代码。output是一个object,里面包含一系列的配置项。
output
object
output.filename配置输出文件的名称,为string类型。
output.path配置输出文件存放在本地的目录(路径),必须是string类型的绝对路径。
path: path.resolve(__dirname, 'dist_[hash]')
output.publicPath配置发布到线上资源的URL前缀,为string类型。默认为空字符串'',即使用相对路径。
''
比如需要将构建的资源上传到CDN服务上,以便加快网页的打开速度。配置代码如下:
filename: '[name]_[chunkhash:8].js' publicPath: 'https://cdn.example.com/assets/'
发布到线上时候,HTML中引入的JavaScript文件如下:
<script src='https://cdn.example.com/assets/a_12345678.js'></script>
线上出现404错误的时候,看下路径有没有错~
还有其他配置请看文档
module配置如何处理模块。
module
module.rules配置模块的读取和解析规则,通常用来配置Loader。其类型是一个数组,数组里每一项都描述了如何去处理部分文件。应用一项rules时大致通过以下方式:
Loader
rules
test
include
exclude
use
enforce
module: { rules: [ { // 命中scss文件 test: /\.scss$/, // 处理顺序从右往左 use: ['style-loader', 'css-loader', 'sass-loader'], // 排除node_modules目录下的文件 exclude: path.resolve(__dirname, 'node_modules'), } ] }
Loader需要传入多个参数的时候的例子:
use: [ { loader:'babel-loader', options:{ cacheDirectory:true, }, // enforce:'post' 的含义是把该 Loader 的执行顺序放到最后 // enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面 enforce:'post' }, // 省略其它 Loader ]
module.noParse配置项可以让webpack忽略对部分没采用模块化的文件的递归解析和处理,这样做有助于提高构建性能。比如:
module: { noParse: (content) => /jquery|lodash/.test(content) }
module.rules.parser属性可以更细粒度的配置哪些模块需要解析,哪些不需要,和noParse配置项的区别在于parser可以精确到语法层面,而noParse只能控制哪些文件不被解析。
noParse
parser
module: { rules: [ { test: /\.js$/, use: ['babel-loader'], parser: { amd: false, // 禁用 AMD commonjs: false, // 禁用 CommonJS ... } } ] }
Resolve配置webpack如何寻找模块所对应的文件。Webpack内置Javascript模块化语法解析功能,默认会采用模块化标准里面约定好的规则去寻找,你也可以按照需求修改默认规则。
Resolve
Webpack
Javascript
resolve.alias配置项通过别名来把原导入的路径映射成一个新的导入路径。如下:
resolve: { alias: { components: './src/components/' } }
当你通过import Button from 'components/button'导入时,实际上被alias等价替换了import Button from './src/components/button'。
import Button from 'components/button'
alias
import Button from './src/components/button'
resolve.modules配置webpack去哪些目录下找第三方模块,默认只会去node_modules目录下寻找。
node_modules
resolve.enforceExtension如果配置为true所有导入语句都必须带有后缀,例如开启前import './foo能正常工作,开启后就必须写成import './foo.js'。
true
import './foo
import './foo.js'
Plugin用于扩展Webpack功能,各种各样的Plugin几乎让Webpack可以做任何构建相关的事情。
Plugin
举个例子:
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); module.exports = { plugins: [ // 所有页面都会用到的公共代码提取到 common 代码块中 new CommonsChunkPlugin({ name: 'common', chunks: ['a', 'b'] }) ] }
在开发环境的时候使用。要配置DevServer,除了在配置文件里面通过devServer传入参数外,还可以通过命令行参数传入。
DevServer
devServer
注意:只有在通过DevServer去启动Webpack时配置项文件里devServer才会生效。
devServer.hot配置是否启用使用DevServer中提到的模块热替换功能。
devServer.host配置项用于配置 DevServer 服务监听的地址。
devServer.port配置项用于配置 DevServer 服务监听的端口,默认使用8080端口。
8080
devServer.https配置HTTPS协议服务。某些情况下你必须使用HTTPS,HTTP2 和 Service Worker 就必须运行在 HTTPS 之上。
devServer: { https: true }
Webpack的运行是一个串行的过程,从启动到结束会执行以下流程:
Loader对文件的转换操纵很耗时,需要让尽可能少的文件被Loader处理。
在使用Loader时可以通过test、include、exclude三个配置项来命中Loader要应用规则的文件。
module.exports = { module: { rules: [ { test: /\.js$/, use: ['babel-loader?cacheDirectory'], include: path.resolve(__dirname, 'src') } ] } }
resolve.modules
resolve.modules用于配置webpack去哪些目录下寻找第三方模块。
resolve.modules的默认值是['node_modules'],含义是先去当前的目录下./node_modules目录下去找想找的模块,以此类推,如果没有找到就去上一级目录../node_modules中找,再没有去上上一级,以此类推...
['node_modules']
./node_modules
../node_modules
如果知道安装的模块在项目的根目录下的./node_modules时候,没有必要按照默认的方式一层层找:
module.exports = { resolve: { modules: [path.resolve(__dirname, 'node_modules')] } }
resolve.alias
resolve.alias配置项通过别名来把原导入路径映射成一个新的导入路径。可以减少耗时的递归解析操作。
module.noParse
module.noParse配置项可以让Webpack忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。
const path = require('path'); module.exports = { module: { // 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理 noParse: [/react\.min\.js$/], } }
HappyPack把任务分解成多个子进程并发执行,子进程处理完后再把结果发送给主进程。减少了总的构建时间。
HappyPack
const HappyPack = require('happypack'); const os = require('os'); const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); module.exports = { module: { rules: [ { test: /\.js$/, loader: 'happypack/loader?id=happyBabel', exclude: /node_modules/ } ] }, plugins: [ new HappyPack({ id: 'happyBabel', loaders: [{ loader: 'babel-loader?cacheDirectory= true', }], // 共享进程池 threadPool: happyThreadPool, // 允许happypack输出日志 verbose: true, }) ] }
例如:
module.export = { watch: true, watchOptions: { // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高 // 默认为 300ms aggregateTimeout: 300, // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的 // 默认每隔1000毫秒询问一次 poll: 1000 } }
由于保存文件的路径和最后编辑时间需要占用内存,定时检查周期检查需要占用CPU以及文件I/O,所以最好减少需要监听的文件数量和降低检查频率。
CPU
I/O
热替换就是当一个源码发生改变的时,只重新编译发生改变的模块,再用新输出的模块替换掉浏览器中对应的老模块。
开启热替换:
webpack-dev-server --hot
区分开发环境和生产环境,进行不同的构建~
CDN又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
CDN 其实是通过优化物理链路层传输过程中的网速有限、丢包等问题来提升网速的。
结合publicPath来处理:
publicPath
const path = require('path'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const { WebPlugin } = require('web-webpack-plugin'); module.exports = { output: { filename: '[name]_[chunkhash:8].js', path: path.resolve(__dirname, './dist'), publicPath: '//js.cdn.com/id/' }, module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ use: ['css-loader?minimize'], publicPath: '//img.cdn.com/id/' }), } ] }, plugins: [ new WebPlugin({ template: './template.html', filename: 'index.html', // 指定存放 CSS 文件的 CDN 目录 URL stylePublicPath: '//css.cdn.com/id/', }), new ExtractTextPlugin({ // 给输出的 CSS 文件名称加上 Hash 值 filename: `[name]_[contenthash:8].css`, }), ] }
将多余的代码移除。
webpack --display-used-exports --optimize-minimize
公共代码的提取。
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); new CommonsChunkPlugin({ // 从哪些 Chunk 中提取 chunks: ['a', 'b'], // 提取出的公共部分形成一个新的 Chunk,这个新 Chunk 的名称 name: 'common' })
对于采用单页应用作为前端架构的网站来说,会面临一个网页需要加载的代码量很大的问题,因为许多功能都做到了一个HTML里面,这会导致网页加载缓慢、交互卡顿、用户体验将非常糟糕。
导致这个问题的根本原因在于一次性的加载所有功能对应的代码,但其实用户每一阶段只可能使用其中一部分功能。 所以解决以上问题的方法就是用户当前需要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载。
Webpack 内置了强大的分割代码的功能去实现按需加载。比如:
main.js
show.js
main.js中:
window.document.getElementById('btn').addEventListener('click', function () { // 当按钮被点击后才去加载 show.js 文件,文件加载成功后执行文件导出的函数 import(/* webpackChunkName: "show" */ './show').then((show) => { show('Webpack'); }) });
show.js中:
module.exports = function (content) { window.alert('Hello ' + content); };
代码中最关键的一句是import(/* webpackChunkName: "show" */ './show'),Webpack 内置了对import(*)语句的支持,当 Webpack 遇到了类似的语句时会这样处理:
import(/* webpackChunkName: "show" */ './show')
import(*)
./show.js
Chunk
import
Promise
then
在工作中具体使用到的时候再按需要进行更改配置项啦~
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered:
No branches or pull requests
构建工具有很多,比如Npm Script任务执行者、Grunt也是任务执行者、Gulp基于流的自动化构建工具、Fis3百度构建工具、Webpack打包模块化
JavaScript
工具和Rollup模块打包工具。这里谈谈用得很频繁的
webpack
构建工具。基本概念
从最基本的概念开始了解:
入口(entry)
entry
是配置模块的入口,必填。出口(output)
output
配置如何输出最终想要的代码。output
是一个object
,里面包含一系列的配置项。output.filename配置输出文件的名称,为string类型。
output.path配置输出文件存放在本地的目录(路径),必须是string类型的绝对路径。
output.publicPath配置发布到线上资源的URL前缀,为string类型。默认为空字符串
''
,即使用相对路径。比如需要将构建的资源上传到CDN服务上,以便加快网页的打开速度。配置代码如下:
发布到线上时候,HTML中引入的
JavaScript
文件如下:线上出现404错误的时候,看下路径有没有错~
还有其他配置请看文档
模块(module)
module
配置如何处理模块。module.rules配置模块的读取和解析规则,通常用来配置
Loader
。其类型是一个数组,数组里每一项都描述了如何去处理部分文件。应用一项rules
时大致通过以下方式:test
、include
、exclude
三个配置项来命中Loader
要应用规则的文件。use
配置项来应用Loader
,可以只应用一个Loader
或者按照从后往前的顺序应用一组Loader
,同时还可以给Loader
传入参数。Loader
执行顺序默认是从右往左执行,通过enforce
选项可以让其中一个Loader
的执行顺序放在前面或者最后。Loader需要传入多个参数的时候的例子:
module.noParse配置项可以让webpack忽略对部分没采用模块化的文件的递归解析和处理,这样做有助于提高构建性能。比如:
module.rules.parser属性可以更细粒度的配置哪些模块需要解析,哪些不需要,和
noParse
配置项的区别在于parser
可以精确到语法层面,而noParse
只能控制哪些文件不被解析。解析(resolve)
Resolve
配置webpack如何寻找模块所对应的文件。Webpack
内置Javascript
模块化语法解析功能,默认会采用模块化标准里面约定好的规则去寻找,你也可以按照需求修改默认规则。resolve.alias配置项通过别名来把原导入的路径映射成一个新的导入路径。如下:
当你通过
import Button from 'components/button'
导入时,实际上被alias
等价替换了import Button from './src/components/button'
。resolve.modules配置
webpack
去哪些目录下找第三方模块,默认只会去node_modules
目录下寻找。resolve.enforceExtension如果配置为
true
所有导入语句都必须带有后缀,例如开启前import './foo
能正常工作,开启后就必须写成import './foo.js'
。插件(plugin)
Plugin
用于扩展Webpack
功能,各种各样的Plugin
几乎让Webpack
可以做任何构建相关的事情。举个例子:
DevServer配置
在开发环境的时候使用。要配置
DevServer
,除了在配置文件里面通过devServer
传入参数外,还可以通过命令行参数传入。注意:只有在通过
DevServer
去启动Webpack
时配置项文件里devServer
才会生效。devServer.hot配置是否启用使用DevServer中提到的模块热替换功能。
devServer.host配置项用于配置 DevServer 服务监听的地址。
devServer.port配置项用于配置 DevServer 服务监听的端口,默认使用
8080
端口。devServer.https配置HTTPS协议服务。某些情况下你必须使用HTTPS,HTTP2 和 Service Worker 就必须运行在 HTTPS 之上。
webpack原理
Webpack的运行是一个串行的过程,从启动到结束会执行以下流程:
webpack优化
缩小文件搜索范围
Loader
对文件的转换操纵很耗时,需要让尽可能少的文件被Loader
处理。在使用Loader时可以通过
test
、include
、exclude
三个配置项来命中Loader
要应用规则的文件。resolve.modules
配置resolve.modules
用于配置webpack去哪些目录下寻找第三方模块。resolve.modules
的默认值是['node_modules']
,含义是先去当前的目录下./node_modules
目录下去找想找的模块,以此类推,如果没有找到就去上一级目录../node_modules
中找,再没有去上上一级,以此类推...如果知道安装的模块在项目的根目录下的
./node_modules
时候,没有必要按照默认的方式一层层找:resolve.alias
配置resolve.alias
配置项通过别名来把原导入路径映射成一个新的导入路径。可以减少耗时的递归解析操作。module.noParse
配置module.noParse
配置项可以让Webpack
忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。把任务分解为多个子进程去并发执行
HappyPack
把任务分解成多个子进程并发执行,子进程处理完后再把结果发送给主进程。减少了总的构建时间。使用自动刷新
例如:
由于保存文件的路径和最后编辑时间需要占用内存,定时检查周期检查需要占用
CPU
以及文件I/O
,所以最好减少需要监听的文件数量和降低检查频率。热替换
热替换就是当一个源码发生改变的时,只重新编译发生改变的模块,再用新输出的模块替换掉浏览器中对应的老模块。
开启热替换:
区分环境
区分开发环境和生产环境,进行不同的构建~
CDN加速
CDN又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
CDN 其实是通过优化物理链路层传输过程中的网速有限、丢包等问题来提升网速的。
结合
publicPath
来处理:tree shaking优化
将多余的代码移除。
提取公共代码
公共代码的提取。
按需加载
对于采用单页应用作为前端架构的网站来说,会面临一个网页需要加载的代码量很大的问题,因为许多功能都做到了一个HTML里面,这会导致网页加载缓慢、交互卡顿、用户体验将非常糟糕。
导致这个问题的根本原因在于一次性的加载所有功能对应的代码,但其实用户每一阶段只可能使用其中一部分功能。 所以解决以上问题的方法就是用户当前需要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载。
Webpack 内置了强大的分割代码的功能去实现按需加载。比如:
main.js
文件,网页会展示一个按钮main.js
文件中只包含监听按钮事件和加载按需加载的代码。show.js
文件,加载成功后再执行show.js
里的函数。main.js中:
show.js中:
代码中最关键的一句是
import(/* webpackChunkName: "show" */ './show')
,Webpack 内置了对import(*)
语句的支持,当 Webpack 遇到了类似的语句时会这样处理:./show.js
为入口新生成一个Chunk
;import
所在语句时才会去加载由Chunk
对应生成的文件。import
返回一个Promise
,当文件加载成功时可以在Promise
的then
方法中获取到show.js
导出的内容。在工作中具体使用到的时候再按需要进行更改配置项啦~
参考
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered: