-
-
Notifications
You must be signed in to change notification settings - Fork 618
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
97dd0f8
commit 1e12553
Showing
14 changed files
with
528 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { CacheProcessor } from "../processor/cache"; | ||
import { CacheRunnerFactory } from "../runner"; | ||
import { BasicCaseCreator } from "../test/creator"; | ||
import { ECompilerType, type TCompilerOptions } from "../type"; | ||
|
||
type TTarget = TCompilerOptions<ECompilerType.Rspack>["target"]; | ||
|
||
const creators: Map< | ||
TTarget, | ||
BasicCaseCreator<ECompilerType.Rspack> | ||
> = new Map(); | ||
|
||
function getCreator(target: TTarget) { | ||
if (!creators.has(target)) { | ||
creators.set( | ||
target, | ||
new BasicCaseCreator({ | ||
clean: true, | ||
describe: true, | ||
target, | ||
steps: ({ name, target }) => [ | ||
new CacheProcessor({ | ||
name, | ||
target: target as TTarget, | ||
compilerType: ECompilerType.Rspack, | ||
configFiles: ["rspack.config.js", "webpack.config.js"] | ||
}) | ||
], | ||
runner: CacheRunnerFactory | ||
}) | ||
); | ||
} | ||
return creators.get(target)!; | ||
} | ||
|
||
export function createCacheCase( | ||
name: string, | ||
src: string, | ||
dist: string, | ||
target: TCompilerOptions<ECompilerType.Rspack>["target"] | ||
) { | ||
const creator = getCreator(target); | ||
creator.create(name, src, dist); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
packages/rspack-test-tools/src/helper/loaders/hot-update.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type { TUpdateOptions } from "../../type"; | ||
|
||
export default function (this: any, c: string) { | ||
let content = c; | ||
if (content.includes("NEXT_HMR")) { | ||
content = ` | ||
${content} | ||
let __hmr_children__ = [...module.children]; | ||
let __hmr_used_exports__ = __hmr_children__.reduce((res, child) => { | ||
res[child] = __webpack_module_cache__[child].exports; | ||
return res; | ||
}, {}); | ||
module.hot.accept(__hmr_children__, () => { | ||
__hmr_children__.forEach((child) => { | ||
const reexports = __webpack_require__(child); | ||
for (let key in reexports) { | ||
Object.defineProperty(__hmr_used_exports__[child], key, { | ||
configurable: true, | ||
enumerable: true, | ||
get: () => reexports[key] | ||
}); | ||
} | ||
}); | ||
}); | ||
`; | ||
} | ||
content = content.replace(/NEXT_HMR/g, "NEXT_HMR.bind(null, module)"); | ||
|
||
const options: TUpdateOptions = this.getOptions(); | ||
const items = content.split(/---+\r?\n/g); | ||
if (items.length <= 1) { | ||
return content; | ||
} | ||
|
||
options.totalUpdates = Math.max(options.totalUpdates, items.length); | ||
options.changedFiles.push(this.resourcePath); | ||
return items[options.updateIndex]; | ||
} |
40 changes: 40 additions & 0 deletions
40
packages/rspack-test-tools/src/helper/plugins/hot-update.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import type { Compiler } from "@rspack/core"; | ||
import type { TUpdateOptions } from "../../type"; | ||
|
||
export class TestHotUpdatePlugin { | ||
constructor(private updateOptions: TUpdateOptions) {} | ||
apply(compiler: Compiler) { | ||
compiler.hooks.beforeRun.tap("TestHotUpdatePlugin", () => { | ||
compiler.modifiedFiles = new Set(this.updateOptions.changedFiles); | ||
this.updateOptions.changedFiles = []; | ||
}); | ||
|
||
compiler.hooks.compilation.tap("TestHotUpdatePlugin", compilation => { | ||
compilation.hooks.additionalTreeRuntimeRequirements.tap( | ||
"HMR_TEST_PLUGIN", | ||
(_chunk: any, set: any) => { | ||
set.add(compiler.webpack.RuntimeGlobals.moduleCache); | ||
} | ||
); | ||
compilation.hooks.runtimeModule.tap( | ||
"HMR_TEST_PLUGIN", | ||
(module: any, _set: any) => { | ||
if (module.constructorName === "DefinePropertyGettersRuntimeModule") { | ||
module.source.source = Buffer.from( | ||
` | ||
__webpack_require__.d = function (exports, definition) { | ||
for (var key in definition) { | ||
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { | ||
Object.defineProperty(exports, key, { configurable: true, enumerable: true, get: definition[key] }); | ||
} | ||
} | ||
}; | ||
`, | ||
"utf-8" | ||
); | ||
} | ||
} | ||
); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./hot-update"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import path from "node:path"; | ||
import { rspack } from "@rspack/core"; | ||
|
||
import { TestHotUpdatePlugin } from "../helper/plugins"; | ||
import { | ||
ECompilerType, | ||
type ITestContext, | ||
type ITestEnv, | ||
type ITestRunner, | ||
type TCompilerOptions, | ||
type TUpdateOptions | ||
} from "../type"; | ||
import { BasicProcessor, type IBasicProcessorOptions } from "./basic"; | ||
|
||
export interface ICacheProcessorOptions<T extends ECompilerType> | ||
extends Omit<IBasicProcessorOptions<T>, "runable"> { | ||
target: TCompilerOptions<T>["target"]; | ||
} | ||
|
||
export class CacheProcessor<T extends ECompilerType> extends BasicProcessor<T> { | ||
protected updateOptions: TUpdateOptions; | ||
protected runner: ITestRunner | null = null; | ||
|
||
constructor(protected _cacheOptions: ICacheProcessorOptions<T>) { | ||
const fakeUpdateLoaderOptions: TUpdateOptions = { | ||
updateIndex: 0, | ||
totalUpdates: 1, | ||
changedFiles: [] | ||
}; | ||
super({ | ||
defaultOptions: CacheProcessor.defaultOptions, | ||
overrideOptions: CacheProcessor.overrideOptions, | ||
findBundle: CacheProcessor.findBundle, | ||
runable: true, | ||
..._cacheOptions | ||
}); | ||
this.updateOptions = fakeUpdateLoaderOptions; | ||
} | ||
|
||
async run(env: ITestEnv, context: ITestContext) { | ||
context.setValue( | ||
this._options.name, | ||
"hotUpdateContext", | ||
this.updateOptions | ||
); | ||
await super.run(env, context); | ||
} | ||
|
||
static findBundle<T extends ECompilerType>( | ||
this: CacheProcessor<T>, | ||
context: ITestContext | ||
): string[] { | ||
const files: string[] = []; | ||
const prefiles: string[] = []; | ||
const compiler = context.getCompiler(this._cacheOptions.name); | ||
if (!compiler) throw new Error("Compiler should exists when find bundle"); | ||
const stats = compiler.getStats(); | ||
if (!stats) throw new Error("Stats should exists when find bundle"); | ||
const info = stats.toJson({ all: false, entrypoints: true }); | ||
if ( | ||
this._cacheOptions.target === "web" || | ||
this._cacheOptions.target === "webworker" | ||
) { | ||
for (const file of info.entrypoints!.main.assets!) { | ||
if (file.name.endsWith(".js")) { | ||
files.push(file.name); | ||
} else { | ||
prefiles.push(file.name); | ||
} | ||
} | ||
} else { | ||
const assets = info.entrypoints!.main.assets!.filter(s => | ||
s.name.endsWith(".js") | ||
); | ||
files.push(assets[assets.length - 1].name); | ||
} | ||
return [...prefiles, ...files]; | ||
} | ||
|
||
async afterAll(context: ITestContext) { | ||
await super.afterAll(context); | ||
if ( | ||
this.updateOptions.updateIndex + 1 !== | ||
this.updateOptions.totalUpdates | ||
) { | ||
throw new Error( | ||
`Should run all hot steps (${this.updateOptions.updateIndex + 1} / ${this.updateOptions.totalUpdates}): ${this._options.name}` | ||
); | ||
} | ||
} | ||
|
||
static defaultOptions<T extends ECompilerType>( | ||
this: CacheProcessor<T>, | ||
context: ITestContext | ||
): TCompilerOptions<T> { | ||
const options = { | ||
context: context.getSource(), | ||
mode: "development", | ||
devtool: false, | ||
output: { | ||
path: context.getDist(), | ||
filename: "bundle.js", | ||
chunkFilename: "[name].chunk.[fullhash].js", | ||
publicPath: "https://test.cases/path/", | ||
library: { type: "commonjs2" } | ||
}, | ||
optimization: { | ||
moduleIds: "named" | ||
}, | ||
target: this._cacheOptions.target, | ||
experiments: { | ||
css: true, | ||
rspackFuture: { | ||
bundlerInfo: { | ||
force: false | ||
} | ||
} | ||
} | ||
} as TCompilerOptions<T>; | ||
|
||
if (this._cacheOptions.compilerType === ECompilerType.Rspack) { | ||
options.plugins ??= []; | ||
(options as TCompilerOptions<ECompilerType.Rspack>).plugins!.push( | ||
new rspack.HotModuleReplacementPlugin() | ||
); | ||
} | ||
|
||
return options; | ||
} | ||
|
||
static overrideOptions<T extends ECompilerType>( | ||
this: CacheProcessor<T>, | ||
context: ITestContext, | ||
options: TCompilerOptions<T> | ||
): void { | ||
if (!options.entry) { | ||
options.entry = "./index.js"; | ||
} | ||
|
||
options.module ??= {}; | ||
for (const cssModuleType of ["css/auto", "css/module", "css"] as const) { | ||
options.module!.generator ??= {}; | ||
options.module!.generator[cssModuleType] ??= {}; | ||
options.module!.generator[cssModuleType]!.exportsOnly ??= | ||
this._cacheOptions.target === "async-node"; | ||
} | ||
options.module.rules ??= []; | ||
options.module.rules.push({ | ||
test: /\.(js|css|json)/, | ||
use: [ | ||
{ | ||
loader: path.resolve(__dirname, "../helper/loaders/hot-update.js"), | ||
options: this.updateOptions | ||
} | ||
] | ||
}); | ||
if (this._cacheOptions.compilerType === ECompilerType.Rspack) { | ||
options.plugins ??= []; | ||
(options as TCompilerOptions<ECompilerType.Rspack>).plugins!.push( | ||
new TestHotUpdatePlugin(this.updateOptions) | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.