Open pomelovico opened 6 years ago
Babel用于将一些新的ES语法特性代码转换为现主流浏览器能够识别的语法代码。
babel是基于插件和预设的形式来使用的,使用babel的时候,需要在当前运行目录下配置.babelrc
文件,该文件是一个标准的json格式文件,用于指定babel在进行转译时采用什么插件以及代码转译的程度。
结合Webpack使用的时候,可以不编写.babelrc
文件,这时候就需要在webpack的配置文件中的module项里,对babel-loader
的options
进行配置,内容和.babelrc
一致
plugins 属性告诉Babel 要使用哪些插件,这些插件可以控制如何转换代码 如:
transform-runtime
插件包名统一以babel-plugin-
为前缀,如babel-plugin-transform-runtime
presets 属性告诉Babel 要转换的源码使用了哪些新的语法特性,一个Presets 对一组新语法的特性提供了支持,多个Presets 可以叠加。Presets 其实是一组Plugins 的集合,每个Plugin 完成一个新语法的转换工作。Presets 是按照ECMAScript 草案来组织的
如:env
、stage-0
,stage-1
,es2015
,react
语法包名统一以babel-preset-
为前缀,如babel-preset-react
;
plugin与presets对每一项都有独立的配置,具体要参考对应的文档
package.json
中可以看到,命令行启动是调用了webpack/bin/webpack.js
,执行文件读取外部配置,然后使用API形式调用。所以最终调用形式都是API接口形式:
const webpack = require('webpack');
//得到编译器对象 const compiler = webpack(config); //执行, compiler.run((err,stats)=>{});
//也可以直接在webpack函数里传入回调函数触发执行: webpack(config,(err,stats)=>{ /有此回调函数时,会自动调用compiler.run(callback)/ })
2. **初始化插件:** Webpack整体构建流程是基于 **事件广播+插件**形式完成的,在执行`compiler.run()`之前,会在compiler上注册所有的插件,插件分内部插件和外部插件,内部插件就是属于Webpack自身构建过程中会使用的插件,外部插件就是我们在`config.plugins`数组中实例化传进去的插件对象。所有的插件都遵照一定规范书写,如下:
```javascript
class MyPlugin {
apply(compiler){
/**
complier的plugin方法会为每一个事件类型维护一个数组,
用以存储插件传递过来的回调函数,
最终所有的事件名和回调队列以键值对的形式保存在了`compiler._plugins`对象上
*/
compiler.plugin('webpack生命周期事件',(compilation.callback)=>{
/**
Webpack在触发生命事件时,就会依次调用注册在该事件数组里的回调,
同时将Webpack的compilation对象传入,
该对象已经保存了当前处理过程中的资源等信息,供插件进行处理
*/
})
compiler.plugin('webpack另一个生命周期事件',(compliation.callback)=>{/*...*/})
}
}
compiler
注册插件形式如下:
//apply方法继承自Tapable类,该方法遍历插件对象数组,然后调用每一个plugin的`apply`方法
compiler.apply([plugin1,plugin2,/*...*/]);
compiler
触发相应的生命周期插件:
compiler.applyPlugins(name);
//根据Compiler继承的Tapable类接口来看,
//不止有一种调用方法,但都以`apply`开头,用于不同情形,比如有异步等等
最重要的,在整个过程中,Webpack会不断的触发各种事件节点,让各类插件参与到当前的构建进度中,从而完成整个构建过程
webpack的生命周期十分复杂而且繁多,囊括了编译阶段前的准备,编译过程,编译结束,资源输出,输出资源优化等等,编写插件时只需找到对应的生命周期节点进行注册,就能做相应的处理
初步看了下webpack的源码,打断点没有走完全程,在并行的控制流代码里彻底混乱,所有代码基于Tapable这个事件发布订阅类,看着令人头大......
但是只要理解清楚Tapable中那几个apply*函数的作用就可以理解webpack为啥会调用不同的函数了,比如有同步顺序执行,异步顺序执行,异步并行执行等区别,大多数方法都是同类方法的变体,参数不一样而已
本篇笔记主要是针对webpack的一些配置项的理解备注,学习自《深入浅出webpack》
module.export.context
webpack寻找相对路径资源的上下文的根目录,一般配置里很少会写
output
output.path
webpack进行打包后的资源存放的本地磁盘路径,必须是一个绝对路径,所以会使用nodejs的path模块进行处理
output.publicPath
用于配置发布到线上服务器的资源的URL前缀,默认为空,所以当不配置的时候,这些资源的路径就是相对路径。举个例子:
我们有如下css文件:
webpack配置文件的output.publicPath配置如下:
打包,找到打包后的代码,可以看到,在自执行的函数里有一个
__webpack_require__.p
就是outputPath:然后看我们的打包后的CSS文件: 可以看到,url设置的背景图片被当作一个模块引入了,通过模块ID在代码里寻找到该模块: ,可以看到,图片资源的路径就是以
publicPath
设置的值为前缀从而拼接得到的url,图片资源名由于在loader中没有设置,所以是默认的随机码此外,有尝试在css的background属性中设置url为外链,打包后的文件中可以看到webpack并不会对外链做处理。
再者,webpack配置的publicPath是针对所有的资源所设置的,在一些loader中也可以进行自行设置
publicPath
,以此可以覆盖掉默认的publicPath
值由上述实践总结到:publicPath的作用就是指定所有会通过url来引用资源的url前缀
output.libraryTarget
output.library
两者结合使用,后者指定导出库的名字,前者指定webpack最终导出的库的形式:
var libraryName = (function(){/*....*/})()
exports[libraryName] = (function(){/*....*/})()
window[libraryName] = (function(){/*....*/})()