esbuild-loader是什么
esbuild-loader是EGOIST出的基于esbuild 的webpack loader和plugin, 不得不说速度真快,具体用法用法也很简单,下面是我直接从readme拷过来的
const { ESBuildPlugin } = require('esbuild-loader')
module.exports = {
module: {
rules: [
{
test: /\.[jt]sx?$/,
loader: 'esbuild-loader',
options: {
// All options are optional
target: 'es2015', // default, or 'es20XX', 'esnext'
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
sourceMap: false // Enable sourcemap
},
},
],
},
plugins: [new ESBuildPlugin()],
}
OK,下面看看怎么实现的
原理
其实loader和plugin主要是让esbuild能在webpack跑起来,首先只支持const exts = ['.js', '.jsx', '.ts', '.tsx']
这四个后缀,先看看loader里面的实现,service就是esbuild起的服务,这个service是在plugin实现起的,服务没有起来,就没办法在loader编译,直接抛出错误,然后在判断资源的后缀是不是我们支持的后缀,不是也抛出错误,最后直接 service.transform 转化代码,传入done
module.exports = async function (source) {
const done = this.async()
const options = getOptions(this)
if (!service) {
return done(
new Error(
`[esbuild-loader] You need to add ESBuildPlugin to your webpack config first`
)
)
}
try {
const ext = path.extname(this.resourcePath)
if (!exts.includes(ext)) {
return done(
new Error(`[esbuild-loader] Unsupported file extension: ${ext}`)
)
}
const result = await service.transform(source, {
target: options.target || 'es2015',
loader: ext.slice(1),
jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
sourcemap: options.sourceMap
})
done(null, result.js, result.jsSourceMap)
} catch (err) {
done(err)
}
}
loader主要就是让esbuild转化代码,plugin就是为了起服务,下面看看plugin,代码如下,如果是正常的build,在run hooks起esbuild的服务,如果是watch模式,在watchrun起服务,最后编译结束的时候,如果我们起了服务,而且不是watch下,那么久关闭service,清空service变量,打完收工,就这两个行数,换上了目前暂时最快的js编译器。
module.exports.ESBuildPlugin = class ESBuildPlugin {
/**
* @param {import('webpack').Compiler} compiler
*/
apply(compiler) {
let watching = false
const startService = async () => {
if (!service) {
service = await esbuild.startService()
}
}
compiler.hooks.run.tapPromise('esbuild', async () => {
await startService()
})
compiler.hooks.watchRun.tapPromise('esbuild', async () => {
watching = true
await startService()
})
compiler.hooks.done.tap('esbuild', () => {
if (!watching && service) {
service.stop()
service = undefined
}
})
}
}