diff --git a/src/rspack/index.ts b/src/rspack/index.ts index 9e6c8483..0d211f1d 100644 --- a/src/rspack/index.ts +++ b/src/rspack/index.ts @@ -32,13 +32,12 @@ export function getRspackPlugin>( } const rawPlugins = toArray(factory(userOptions!, meta)) for (const plugin of rawPlugins) { - // transform hook - if (plugin.transform) { + // load hook + if (plugin.load) { const use: RuleSetUseItem = { - loader: TRANSFORM_LOADER, + loader: LOAD_LOADER, options: { plugin }, } - compiler.options.module.rules.unshift({ enforce: plugin.enforce, include: /.*/, @@ -46,12 +45,13 @@ export function getRspackPlugin>( }) } - // load hook - if (plugin.load) { + // transform hook + if (plugin.transform) { const use: RuleSetUseItem = { - loader: LOAD_LOADER, + loader: TRANSFORM_LOADER, options: { plugin }, } + compiler.options.module.rules.unshift({ enforce: plugin.enforce, include: /.*/, diff --git a/src/webpack/index.ts b/src/webpack/index.ts index 278bdc25..5b8f98db 100644 --- a/src/webpack/index.ts +++ b/src/webpack/index.ts @@ -58,27 +58,6 @@ export function getWebpackPlugin>( const externalModules = new Set() - // transform hook - if (plugin.transform) { - const useLoader: RuleSetUseItem[] = [{ - loader: `${TRANSFORM_LOADER}?unpluginName=${encodeURIComponent(plugin.name)}`, - }] - const useNone: RuleSetUseItem[] = [] - compiler.options.module.rules.unshift({ - enforce: plugin.enforce, - use: (data: { resource: string | null; resourceQuery: string }) => { - if (data.resource == null) - return useNone - - const id = normalizeAbsolutePath(data.resource + (data.resourceQuery || '')) - if (!plugin.transformInclude || plugin.transformInclude(id)) - return useLoader - - return useNone - }, - }) - } - // resolveId hook if (plugin.resolveId) { let vfs = compiler.options.plugins.find(i => i instanceof VirtualModulesPlugin) as VirtualModulesPlugin @@ -177,6 +156,27 @@ export function getWebpackPlugin>( }) } + // transform hook + if (plugin.transform) { + const useLoader: RuleSetUseItem[] = [{ + loader: `${TRANSFORM_LOADER}?unpluginName=${encodeURIComponent(plugin.name)}`, + }] + const useNone: RuleSetUseItem[] = [] + compiler.options.module.rules.unshift({ + enforce: plugin.enforce, + use: (data: { resource: string | null; resourceQuery: string }) => { + if (data.resource == null) + return useNone + + const id = normalizeAbsolutePath(data.resource + (data.resourceQuery || '')) + if (!plugin.transformInclude || plugin.transformInclude(id)) + return useLoader + + return useNone + }, + }) + } + if (plugin.webpack) plugin.webpack(compiler) diff --git a/test/fixtures/load/__test__/build.test.ts b/test/fixtures/load/__test__/build.test.ts new file mode 100644 index 00000000..1388a59c --- /dev/null +++ b/test/fixtures/load/__test__/build.test.ts @@ -0,0 +1,35 @@ +import { resolve } from 'path' +import fs from 'fs-extra' +import { describe, expect, it } from 'vitest' + +const r = (...args: string[]) => resolve(__dirname, '../dist', ...args) + +describe('load-called-before-transform', () => { + it('vite', async () => { + const content = await fs.readFile(r('vite/main.js.mjs'), 'utf-8') + expect(content).toContain('it is a msg -> through the load hook -> transform-[Injected Vite]') + }) + + it('rollup', async () => { + const content = await fs.readFile(r('rollup/main.js'), 'utf-8') + + expect(content).toContain('it is a msg -> through the load hook -> transform-[Injected Rollup]') + }) + + it('webpack', async () => { + const content = await fs.readFile(r('webpack/main.js'), 'utf-8') + + expect(content).toContain('it is a msg -> through the load hook -> transform-[Injected Webpack]') + }) + + it('esbuild', async () => { + const content = await fs.readFile(r('esbuild/main.js'), 'utf-8') + expect(content).toContain('it is a msg -> through the load hook -> transform-[Injected Esbuild]') + }) + + it.skipIf(process.env.SKIP_RSPACK === 'true')('rspack', async () => { + const content = await fs.readFile(r('rspack/main.js'), 'utf-8') + + expect(content).toContain('it is a msg -> through the load hook -> transform-[Injected Rspack]') + }) +}) diff --git a/test/fixtures/load/esbuild.config.js b/test/fixtures/load/esbuild.config.js new file mode 100644 index 00000000..f6c8d4bf --- /dev/null +++ b/test/fixtures/load/esbuild.config.js @@ -0,0 +1,12 @@ +const { build } = require('esbuild') +const { esbuild } = require('./unplugin') + +build({ + entryPoints: ['src/main.js'], + bundle: true, + outdir: 'dist/esbuild', + sourcemap: true, + plugins: [ + esbuild({ msg: 'Esbuild' }), + ], +}) diff --git a/test/fixtures/load/rollup.config.js b/test/fixtures/load/rollup.config.js new file mode 100644 index 00000000..f19be237 --- /dev/null +++ b/test/fixtures/load/rollup.config.js @@ -0,0 +1,12 @@ +const { rollup } = require('./unplugin') + +export default { + input: './src/main.js', + output: { + dir: './dist/rollup', + sourcemap: true, + }, + plugins: [ + rollup({ msg: 'Rollup' }), + ], +} diff --git a/test/fixtures/load/rspack.config.js b/test/fixtures/load/rspack.config.js new file mode 100644 index 00000000..e9261338 --- /dev/null +++ b/test/fixtures/load/rspack.config.js @@ -0,0 +1,14 @@ +const { resolve } = require('path') +const { rspack } = require('./unplugin') + +/** @type import('@rspack/core').Configuration */ +module.exports = { + mode: 'development', + entry: resolve(__dirname, 'src/main.js'), + output: { + path: resolve(__dirname, 'dist/rspack'), + filename: 'main.js', + }, + plugins: [rspack({ msg: 'Rspack' })], + devtool: 'source-map', +} diff --git a/test/fixtures/load/src/main.js b/test/fixtures/load/src/main.js new file mode 100644 index 00000000..c2c0c3a4 --- /dev/null +++ b/test/fixtures/load/src/main.js @@ -0,0 +1,3 @@ +import msg1 from './msg' + +console.log(msg1) diff --git a/test/fixtures/load/src/msg.js b/test/fixtures/load/src/msg.js new file mode 100644 index 00000000..d3239afc --- /dev/null +++ b/test/fixtures/load/src/msg.js @@ -0,0 +1 @@ +export default 'it is a msg' diff --git a/test/fixtures/load/unplugin.js b/test/fixtures/load/unplugin.js new file mode 100644 index 00000000..f8055002 --- /dev/null +++ b/test/fixtures/load/unplugin.js @@ -0,0 +1,45 @@ +const fs = require('fs') +const MagicString = require('magic-string') +const { createUnplugin } = require('unplugin') + +const targetFileReg = /(?:\/|\\)msg\.js$/ +module.exports = createUnplugin((options) => { + return { + name: 'load-called-before-transform', + loadInclude(id) { + return targetFileReg.test(id) + }, + load(id) { + const code = fs.readFileSync(id, { encoding: 'utf-8' }) + const str = new MagicString(code) + const _index = code.indexOf('msg') + const loadInjectedCode = 'msg -> through the load hook -> __unplugin__' + + str.overwrite(_index, _index + 'msg'.length, loadInjectedCode) + return str.toString() + }, + transformInclude(id) { + return targetFileReg.test(id) + }, + transform(code, id) { + const s = new MagicString(code) + const index = code.indexOf('__unplugin__') + if (index === -1) + return null + + const injectedCode = `transform-[Injected ${options.msg}]` + + if (code.includes(injectedCode)) + throw new Error('File was already transformed') + + s.overwrite(index, index + '__unplugin__'.length, injectedCode) + return { + code: s.toString(), + map: s.generateMap({ + source: id, + includeContent: true, + }), + } + }, + } +}) diff --git a/test/fixtures/load/vite.config.js b/test/fixtures/load/vite.config.js new file mode 100644 index 00000000..e02c38e6 --- /dev/null +++ b/test/fixtures/load/vite.config.js @@ -0,0 +1,18 @@ +const { resolve } = require('path') +const { vite } = require('./unplugin') + +module.exports = { + root: __dirname, + plugins: [ + vite({ msg: 'Vite' }), + ], + build: { + lib: { + entry: resolve(__dirname, 'src/main.js'), + name: 'main', + fileName: 'main.js', + }, + outDir: 'dist/vite', + sourcemap: true, + }, +} diff --git a/test/fixtures/load/webpack.config.js b/test/fixtures/load/webpack.config.js new file mode 100644 index 00000000..08fd34a7 --- /dev/null +++ b/test/fixtures/load/webpack.config.js @@ -0,0 +1,15 @@ +const { resolve } = require('path') +const { webpack } = require('./unplugin') + +module.exports = { + mode: 'development', + entry: resolve(__dirname, 'src/main.js'), + output: { + path: resolve(__dirname, 'dist/webpack'), + filename: 'main.js', + }, + plugins: [ + webpack({ msg: 'Webpack' }), + ], + devtool: 'source-map', +}