实现babel-loader
本节实现babel-loader
安装插件
shell
yarn add @babel/core@^7.4.5 @babel/preset-env@^7.4.5 -D
- @babel/core,babel的核心模块
- @babel/preset-env,把高版本语法转换为低版本语法
并没有安装 babel-loader,我们自己手写一个。
再安装一个工具类loader-utils,用来拿到babel的预设
shell
yarn add loader-utils@^1.2.3 -D
代码
修改配置文件
js
// webpack\webpack-loader\webpack.config.js
let path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 使用我们自己写的babel-loader
options: {
presets: [ // 增加预设
'@babel/preset-env'
]
}
}
}
]
},
resolveLoader: {
// 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
/* alias: { // loader的别名
loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
} */
}
}
新建babel-loader
js
// webpack\webpack-loader\loaders\babel-loader.js
let babel = require('@babel/core') // babel内部是用这个核心模块来转化的
let loaderUtils = require('loader-utils') // webpack loader的工具类,这里用来拿到预设
/*
babel-loader
需要拿到预设,告诉babel用预设转换模块
options: {
presets: [
'@babel/preset-env'
]}
为了拿到配置中的预设,使用一个工具库,loader-utils
}
*/
function loader(source) {
console.log('babel-loader 加载了');
console.log(this.resourcePath); // F:\code\note_code\webpack\webpack-loader\src\index.js
// console.log(Object.keys(this));
let optios = loaderUtils.getOptions(this) // 使用工具包,拿到webpack中的babel的预设
// optios = { presets: [ '@babel/preset-env' ] }
let cb = this.async() // webpack执行loader中自带的方法,用来返回一个回调函数
// 异步返回结果的时候使用
// 开始转换
babel.transform(source, {
...optios,
sourceMap: true, // 转换的映射文件
filename: this.resourcePath.split('/').pop(), // 映射文件的名字 index.js
// this.resourcePath = F:\code\note_code\webpack\webpack-loader\src\index.js
}, (err, result) => { // 异步转换,所以需要使用回调返回结果
cb(err, result.code, result.map) // 第一个参数是错误,第二个参数是返回结果
// 同时生成一下sourceMap
})
}
module.exports = loader
/*
Object.keys(this) = [
'version', 'emitWarning',
'emitError', 'getLogger',
'exec', 'resolve',
'getResolve', 'emitFile',
'rootContext', 'webpack',
'sourceMap', 'mode',
'_module', '_compilation',
'_compiler', 'fs',
'target', 'loadModule',
'context', 'loaderIndex',
'loaders', 'resourcePath',
'resourceQuery', 'async',
'callback', 'cacheable',
'addDependency', 'dependency',
'addContextDependency', 'getDependencies',
'getContextDependencies', 'clearDependencies',
'resource', 'request',
'remainingRequest', 'currentRequest',
'previousRequest', 'query',
'data'
]
*/
修改index.js
js
// webpack\webpack-loader\src\index.js
// 写一些ES6的语法,测试自己写babel-loader
class A {
constructor() {
this.name = 'cheny && xzz'
}
getName() {
return this.name
}
}
let a = new A()
console.log(a.getName());
打包一下看下结果,成功
总结
babel-loader实现,关键是使用第三方包来转换es6代码
loaderUtils,可以获取到webpack中预设的babel转换方式
jslet loaderUtils = require('loader-utils') // webpack loader的工具类,这里用来拿到预设 function loader(source) { console.log('babel-loader 加载了'); console.log(this.resourcePath); // F:\code\note_code\webpack\webpack-loader\src\index.js // console.log(Object.keys(this)); let optios = loaderUtils.getOptions(this) // 使用工具包,拿到webpack中的babel的预设 // optios = { presets: [ '@babel/preset-env' ] } } module.exports = loader
webpack在调用loader时,我们在自定义loader上能访问到webpack的this对象,上面挂载了很多方法和属性
jsfunction loader(source) { // console.log(Object.keys(this)); } module.exports = loader /* Object.keys(this) = [ 'version', 'emitWarning', 'emitError', 'getLogger', 'exec', 'resolve', 'getResolve', 'emitFile', 'rootContext', 'webpack', 'sourceMap', 'mode', '_module', '_compilation', '_compiler', 'fs', 'target', 'loadModule', 'context', 'loaderIndex', 'loaders', 'resourcePath', 'resourceQuery', 'async', 'callback', 'cacheable', 'addDependency', 'dependency', 'addContextDependency', 'getDependencies', 'getContextDependencies', 'clearDependencies', 'resource', 'request', 'remainingRequest', 'currentRequest', 'previousRequest', 'query', 'data' ] */
在使用
@babel/core
来转换es6代码时,结果转换的方式是异步的,需要使用回调的方式把结果回传回去,可以在this上拿到回传的回调方法jslet cb = this.async() // webpack执行loader中自带的方法,用来返回一个回调函数
babel-loader的全部代码
jslet babel = require('@babel/core') // babel内部是用这个核心模块来转化的 let loaderUtils = require('loader-utils') // webpack loader的工具类,这里用来拿到预设 function loader(source) { console.log('babel-loader 加载了'); console.log(this.resourcePath); // F:\code\note_code\webpack\webpack-loader\src\index.js // console.log(Object.keys(this)); let optios = loaderUtils.getOptions(this) // 使用工具包,拿到webpack中的babel的预设 // optios = { presets: [ '@babel/preset-env' ] } let cb = this.async() // webpack执行loader中自带的方法,用来返回一个回调函数 // 异步返回结果的时候使用 // 开始转换 babel.transform(source, { ...optios, sourceMap: true, // 转换的映射文件 filename: this.resourcePath.split('/').pop(), // 映射文件的名字 index.js // this.resourcePath = F:\code\note_code\webpack\webpack-loader\src\index.js }, (err, result) => { // 异步转换,所以需要使用回调返回结果 cb(err, result.code, result.map) // 第一个参数是错误,第二个参数是返回结果 // 同时生成一下sourceMap }) } module.exports = loader