Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/rspack/loaders/load.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { LoaderContext } from '@rspack/core'
import type { ResolvedUnpluginOptions } from '../../types'
import { normalizeObjectHook } from '../../utils/filter'
import { normalizeAbsolutePath } from '../../utils/webpack-like'
import { normalizeAbsolutePath, unescapeResourcePath } from '../../utils/webpack-like'
import { createBuildContext, createContext } from '../context'
import { decodeVirtualModuleId, isVirtualModuleId } from '../utils'

Expand All @@ -16,6 +16,8 @@ export default async function load(this: LoaderContext, source: string, map: any
if (isVirtualModuleId(id, plugin))
id = decodeVirtualModuleId(id, plugin)

id = unescapeResourcePath(id)

const context = createContext(this)
const { handler } = normalizeObjectHook('load', plugin.load)
try {
Expand Down
5 changes: 3 additions & 2 deletions src/rspack/loaders/transform.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { LoaderContext } from '@rspack/core'
import type { ResolvedUnpluginOptions } from '../../types'
import { normalizeObjectHook } from '../../utils/filter'
import { unescapeResourcePath } from '../../utils/webpack-like'
import { createBuildContext, createContext } from '../context'

export default async function transform(
Expand All @@ -13,10 +14,10 @@ export default async function transform(
if (!plugin?.transform)
return callback(null, source, map)

const id = this.resource
const id = unescapeResourcePath(this.resource)
const context = createContext(this)
const { handler, filter } = normalizeObjectHook('transform', plugin.transform)
if (!filter(this.resource, source))
if (!filter(id, source))
return callback(null, source, map)

try {
Expand Down
6 changes: 6 additions & 0 deletions src/utils/webpack-like.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,9 @@ export function normalizeAbsolutePath(path: string): string {
else
return path
}

export function unescapeResourcePath(path: string): string {
return path
.replace(/\0(.)/g, '$1')
.replace(/\u200B#/g, '#')
}
4 changes: 3 additions & 1 deletion src/webpack/loaders/load.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { LoaderContext } from 'webpack'
import type { ResolvedUnpluginOptions } from '../../types'
import { normalizeObjectHook } from '../../utils/filter'
import { normalizeAbsolutePath } from '../../utils/webpack-like'
import { normalizeAbsolutePath, unescapeResourcePath } from '../../utils/webpack-like'
import { createBuildContext, createContext } from '../context'

export default async function load(this: LoaderContext<any>, source: string, map: any): Promise<void> {
Expand All @@ -15,6 +15,8 @@ export default async function load(this: LoaderContext<any>, source: string, map
if (id.startsWith(plugin.__virtualModulePrefix))
id = decodeURIComponent(id.slice(plugin.__virtualModulePrefix.length))

id = unescapeResourcePath(id)

const context = createContext(this)
const { handler } = normalizeObjectHook('load', plugin.load)
const res = await handler.call(
Expand Down
6 changes: 4 additions & 2 deletions src/webpack/loaders/transform.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { LoaderContext } from 'webpack'
import type { ResolvedUnpluginOptions } from '../../types'
import { normalizeObjectHook } from '../../utils/filter'
import { unescapeResourcePath } from '../../utils/webpack-like'
import { createBuildContext, createContext } from '../context'

export default async function transform(this: LoaderContext<any>, source: string, map: any): Promise<void> {
Expand All @@ -10,9 +11,10 @@ export default async function transform(this: LoaderContext<any>, source: string
if (!plugin?.transform)
return callback(null, source, map)

const id = unescapeResourcePath(this.resource)
const context = createContext(this)
const { handler, filter } = normalizeObjectHook('transform', plugin.transform)
if (!filter(this.resource, source))
if (!filter(id, source))
return callback(null, source, map)

try {
Expand All @@ -26,7 +28,7 @@ export default async function transform(this: LoaderContext<any>, source: string
},
}, this._compiler!, this._compilation, this, map), context),
source,
this.resource,
id,
)

if (res == null)
Expand Down
29 changes: 29 additions & 0 deletions test/fixtures/hash-path/__test__/build.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import fs from 'node:fs/promises'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
import { onlyBun } from '../../../utils'

const r = (...args: string[]) => resolve(__dirname, '../dist', ...args)
const expected = 'it is a msg -> through the load hook -> transform#hash'
const cases: Array<[string, string]> = [
['vite', 'vite/main.js.mjs'],
['rollup', 'rollup/main.js'],
['webpack', 'webpack/main.js'],
['esbuild', 'esbuild/main.js'],
['rspack', 'rspack/main.js'],
['farm', 'farm/main.js'],
]

describe('hash-path hooks', () => {
for (const [name, file] of cases) {
it(name, async () => {
const content = await fs.readFile(r(file), 'utf-8')
expect(content).toContain(expected)
})
}

onlyBun('bun', async () => {
const content = await fs.readFile(r('bun/main.js'), 'utf-8')
expect(content).toContain(expected)
})
})
8 changes: 8 additions & 0 deletions test/fixtures/hash-path/bun.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const Bun = require('bun')
const { bun } = require('./unplugin')

await Bun.build({
entrypoints: ['./src/main.js'],
outdir: './dist/bun',
plugins: [bun({ msg: 'Bun' })],
})
12 changes: 12 additions & 0 deletions test/fixtures/hash-path/esbuild.config.js
Original file line number Diff line number Diff line change
@@ -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' }),
],
})
23 changes: 23 additions & 0 deletions test/fixtures/hash-path/farm.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { farm } = require('./unplugin')

/**
* @type {import('@farmfe/core').UserConfig}
*/
module.exports = {
compilation: {
persistentCache: false,
input: {
index: './src/main.js',
},
presetEnv: false,
output: {
entryFilename: 'main.[ext]',
path: './dist/farm',
targetEnv: 'node',
format: 'cjs',
},
},
plugins: [
farm({ msg: 'Farm' }),
],
}
12 changes: 12 additions & 0 deletions test/fixtures/hash-path/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { rollup } = require('./unplugin')

export default {
input: './src/main.js',
output: {
dir: './dist/rollup',
sourcemap: true,
},
plugins: [
rollup({ msg: 'Rollup' }),
],
}
14 changes: 14 additions & 0 deletions test/fixtures/hash-path/rspack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { resolve } = require('node: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',
}
3 changes: 3 additions & 0 deletions test/fixtures/hash-path/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import msg from 'hash-msg#raw'

console.log(msg)
1 change: 1 addition & 0 deletions test/fixtures/hash-path/src/msg#hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'it is a msg#hash'
73 changes: 73 additions & 0 deletions test/fixtures/hash-path/unplugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const fs = require('node:fs')
const { resolve } = require('node:path')
const MagicString = require('magic-string')
const { createUnplugin } = require('unplugin')

const sourceId = 'hash-msg#raw'
const resolvedId = resolve(__dirname, 'src/msg#hash.js')

function assertUnescapedId(hook, id) {
if (id.includes('\0') || id.includes('\u200B#'))
throw new Error(`${hook} received escaped id: ${JSON.stringify(id)}`)
}

module.exports = createUnplugin(() => {
return {
name: 'hash-path-hooks',
resolveId(id) {
assertUnescapedId('resolveId', id)

if (id === sourceId)
return resolvedId

if (id.includes('hash-msg'))
throw new Error(`resolveId received unexpected id: ${JSON.stringify(id)}`)
},
loadInclude(id) {
assertUnescapedId('loadInclude', id)

// Return true so the test always exercises `load`.
return true
},
load(id) {
assertUnescapedId('load', id)

const code = fs.readFileSync(id, 'utf-8')
if (id !== resolvedId)
return code

const s = new MagicString(code)
const index = code.indexOf('msg#hash')
if (index === -1)
throw new Error(`load expected token "msg#hash" in ${JSON.stringify(id)}`)

s.overwrite(index, index + 'msg#hash'.length, 'msg -> through the load hook -> __unplugin__#hash')
return s.toString()
},
transformInclude(id) {
assertUnescapedId('transformInclude', id)

// Return true so the test always exercises `transform`.
return true
},
transform(code, id) {
assertUnescapedId('transform', id)
if (id !== resolvedId)
return code

const s = new MagicString(code)
const index = code.indexOf('__unplugin__')
if (index === -1)
throw new Error(`transform expected token "__unplugin__" in ${JSON.stringify(id)}`)

s.overwrite(index, index + '__unplugin__'.length, 'transform')
return {
code: s.toString(),
map: s.generateMap({
source: id,
includeContent: true,
}),
}
},
}
})
18 changes: 18 additions & 0 deletions test/fixtures/hash-path/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { resolve } = require('node: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,
},
}
15 changes: 15 additions & 0 deletions test/fixtures/hash-path/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { resolve } = require('node: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',
}
1 change: 1 addition & 0 deletions test/fixtures/load/unplugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const MagicString = require('magic-string')
const { createUnplugin } = require('unplugin')

const targetFileReg = /(?:\/|\\)msg\.js$/

module.exports = createUnplugin((options) => {
return {
name: 'load-called-before-transform',
Expand Down
Loading