From c325e22f0cdf074f76baa01fb65a951e15f0346b Mon Sep 17 00:00:00 2001 From: fi3ework Date: Mon, 14 Oct 2024 14:33:40 +0800 Subject: [PATCH] fix: do not use CJS methods in ESM --- package.json | 4 +- packages/core/src/config.ts | 117 +++++++++++-- .../core/src/plugins/{cjsShim.ts => shims.ts} | 28 ++- packages/core/src/types/config/index.ts | 21 +++ .../tests/__snapshots__/config.test.ts.snap | 5 + tests/benchmark/index.bench.ts | 6 +- tests/integration/alias/index.test.ts | 2 +- tests/integration/asset/index.test.ts | 10 +- tests/integration/async-chunks/index.test.ts | 2 +- .../integration/auto-extension/index.test.ts | 12 +- tests/integration/auto-external/index.test.ts | 10 +- tests/integration/banner-footer/index.test.ts | 5 +- tests/integration/bundle-false/index.test.ts | 10 +- tests/integration/copy/index.test.ts | 2 +- tests/integration/decorators/index.test.ts | 4 +- tests/integration/define/index.test.ts | 2 +- tests/integration/dts/index.test.ts | 52 ++++-- tests/integration/entry/index.test.ts | 6 +- .../integration/extension-alias/index.test.ts | 2 +- .../external-helpers/index.test.ts | 8 +- tests/integration/externals/index.test.ts | 6 +- tests/integration/minify/index.test.ts | 2 +- tests/integration/require/index.test.ts | 8 +- .../require/require-resolve/other.ts | 1 + tests/integration/resolve/index.test.ts | 12 +- tests/integration/shims/cjs/rslib.config.ts | 9 +- tests/integration/shims/cjs/src/index.ts | 1 + tests/integration/shims/esm/rslib.config.ts | 36 +++- .../shims/esm/rslibShimsDisabled.config.ts | 15 ++ tests/integration/shims/esm/src/index.ts | 7 +- tests/integration/shims/esm/src/ok.cjs | 1 + tests/integration/shims/esm/src/require.ts | 4 + tests/integration/shims/index.test.ts | 92 ++++++++-- tests/integration/sourcemap/index.test.ts | 7 +- .../style/css-modules/index.test.ts | 10 +- tests/integration/style/css/index.test.ts | 4 +- tests/integration/style/less/index.test.ts | 6 +- .../style/lightningcss/index.test.ts | 4 +- tests/integration/style/postcss/index.test.ts | 4 +- .../style/redirect-style-false/index.test.ts | 2 +- tests/integration/style/sass/index.test.ts | 4 +- .../style/style-inject/index.test.ts | 2 +- .../style/tailwindcss/index.test.ts | 2 +- tests/integration/syntax/index.test.ts | 4 +- .../transform-import/index.test.ts | 4 +- tests/integration/tsconfig/index.test.ts | 2 +- tests/scripts/shared.ts | 46 +++-- website/docs/en/_meta.json | 5 + website/docs/en/config/_meta.json | 12 ++ website/docs/en/config/index.mdx | 3 + website/docs/en/config/lib/shims.mdx | 164 ++++++++++++++++++ 51 files changed, 629 insertions(+), 158 deletions(-) rename packages/core/src/plugins/{cjsShim.ts => shims.ts} (52%) create mode 100644 tests/integration/require/require-resolve/other.ts create mode 100644 tests/integration/shims/esm/rslibShimsDisabled.config.ts create mode 100644 tests/integration/shims/esm/src/ok.cjs create mode 100644 tests/integration/shims/esm/src/require.ts create mode 100644 website/docs/en/config/_meta.json create mode 100644 website/docs/en/config/index.mdx create mode 100644 website/docs/en/config/lib/shims.mdx diff --git a/package.json b/package.json index cd53efb3..b9a43ff0 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "test": "pnpm run test:unit && pnpm run test:integration && pnpm run test:e2e", "test:benchmark": "cd ./tests && pnpm run test:benchmark", "test:e2e": "pnpm run build:examples && cd tests && pnpm run test:e2e", - "test:integration": "vitest run --project integration", - "test:integration:watch": "vitest --project integration", + "test:integration": "NODE_OPTIONS='--experimental-vm-modules' vitest run --project integration", + "test:integration:watch": "NODE_OPTIONS='--experimental-vm-modules' vitest --project integration", "test:unit": "vitest run --project unit*", "test:unit:watch": "vitest --project unit*", "testu": "pnpm run test:unit -u && pnpm run test:integration -u", diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index d3855029..5891b2bb 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -24,7 +24,10 @@ import { cssExternalHandler, isCssGlobalFile, } from './css/cssConfig'; -import { pluginCjsShim } from './plugins/cjsShim'; +import { + pluginCjsImportMetaUrlShim, + pluginEsmRequireShim, +} from './plugins/shims'; import type { AutoExternal, BannerAndFooter, @@ -32,11 +35,13 @@ import type { LibConfig, PkgJson, Redirect, + ResolvedShims, RsbuildConfigOutputTarget, RslibConfig, RslibConfigAsyncFn, RslibConfigExport, RslibConfigSyncFn, + Shims, Syntax, } from './types'; import { getDefaultExtension } from './utils/extension'; @@ -447,12 +452,16 @@ export async function createConstantRsbuildConfig(): Promise { const composeFormatConfig = (format: Format): RsbuildConfig => { const jsParserOptions = { - importMeta: false, - requireResolve: false, - requireDynamic: false, - requireAsExpression: false, - importDynamic: false, - }; + cjs: { + requireResolve: false, + requireDynamic: false, + requireAsExpression: false, + }, + esm: { + importMeta: false, + importDynamic: false, + }, + } as const; switch (format) { case 'esm': @@ -461,7 +470,10 @@ const composeFormatConfig = (format: Format): RsbuildConfig => { rspack: { module: { parser: { - javascript: jsParserOptions, + javascript: { + ...jsParserOptions.esm, + ...jsParserOptions.cjs, + }, }, }, optimization: { @@ -486,12 +498,11 @@ const composeFormatConfig = (format: Format): RsbuildConfig => { }; case 'cjs': return { - plugins: [pluginCjsShim()], tools: { rspack: { module: { parser: { - javascript: jsParserOptions, + javascript: { ...jsParserOptions.esm, ...jsParserOptions.cjs }, }, }, output: { @@ -531,6 +542,85 @@ const composeFormatConfig = (format: Format): RsbuildConfig => { } }; +const resolveShims = (shims?: Shims) => { + const resolvedShims = { + cjs: { + 'import.meta.url': true, + }, + esm: { + __filename: true, + __dirname: true, + require: false, + }, + }; + + if (!shims) { + return resolvedShims; + } + + if (shims.cjs) { + if (typeof shims.cjs === 'boolean') { + if (shims.cjs === true) { + resolvedShims.cjs['import.meta.url'] = true; + } else { + resolvedShims.cjs['import.meta.url'] = false; + } + } else { + resolvedShims.cjs['import.meta.url'] = + shims.cjs['import.meta.url'] ?? false; + } + } + + if (shims.esm) { + if (typeof shims.esm === 'boolean') { + if (shims.esm === true) { + resolvedShims.esm.__filename = true; + resolvedShims.esm.__dirname = true; + resolvedShims.esm.require = true; + } + } else { + resolvedShims.esm.__filename = shims.esm.__filename ?? false; + resolvedShims.esm.__dirname = shims.esm.__dirname ?? false; + resolvedShims.esm.require = shims.esm.require ?? false; + } + } + + return resolvedShims; +}; + +const composeShimsConfig = ( + format: Format, + resolvedShims: ResolvedShims, +): RsbuildConfig => { + switch (format) { + case 'esm': + return { + tools: { + rspack: { + node: { + // "__dirname" and "__filename" shims will automatically be enabled when `output.module` is `true` + __dirname: resolvedShims.esm.__dirname ? 'node-module' : false, + __filename: resolvedShims.esm.__filename ? 'node-module' : false, + }, + }, + }, + plugins: [resolvedShims.esm.require && pluginEsmRequireShim()].filter( + Boolean, + ), + }; + case 'cjs': + return { + plugins: [ + resolvedShims.cjs['import.meta.url'] && pluginCjsImportMetaUrlShim(), + ].filter(Boolean), + }; + case 'umd': + return {}; + default: + throw new Error(`Unsupported format: ${format}`); + } +}; + export const composeModuleImportWarn = (request: string): string => { return `The externalized commonjs request ${color.green(`"${request}"`)} will use ${color.blue('"module"')} external type in ESM format. If you want to specify other external type, considering set the request and type with ${color.blue('"output.externals"')}.`; }; @@ -832,9 +922,6 @@ const composeTargetConfig = ( tools: { rspack: { target: ['node'], - // "__dirname" and "__filename" shims will automatically be enabled when `output.module` is `true`, - // and leave them as-is in the rest of the cases. Leave the comments here to explain the behavior. - // { node: { __dirname: ..., __filename: ... } } }, }, output: { @@ -915,6 +1002,8 @@ async function composeLibRsbuildConfig(config: LibConfig, configPath: string) { externalHelpers = false, redirect = {}, } = config; + const resolvedShims = resolveShims(config.shims); + const shimsConfig = composeShimsConfig(format!, resolvedShims); const formatConfig = composeFormatConfig(format!); const externalHelpersConfig = composeExternalHelpersConfig( externalHelpers, @@ -967,6 +1056,7 @@ async function composeLibRsbuildConfig(config: LibConfig, configPath: string) { return mergeRsbuildConfig( formatConfig, + shimsConfig, externalHelpersConfig, // externalsWarnConfig should before other externals config externalsWarnConfig, @@ -1046,6 +1136,7 @@ export async function composeCreateRsbuildConfig( 'banner', 'footer', 'dts', + 'shims', ]), ), }; diff --git a/packages/core/src/plugins/cjsShim.ts b/packages/core/src/plugins/shims.ts similarity index 52% rename from packages/core/src/plugins/cjsShim.ts rename to packages/core/src/plugins/shims.ts index 5c9217e7..922c3b4a 100644 --- a/packages/core/src/plugins/cjsShim.ts +++ b/packages/core/src/plugins/shims.ts @@ -1,4 +1,4 @@ -import type { RsbuildPlugin } from '@rsbuild/core'; +import { type RsbuildPlugin, rspack } from '@rsbuild/core'; const importMetaUrlShim = `/*#__PURE__*/ (function () { return typeof document === 'undefined' @@ -11,9 +11,8 @@ const importMetaUrlShim = `/*#__PURE__*/ (function () { // - Replace `import.meta.url` with `importMetaUrl`. // - Inject `importMetaUrl` to the end of the module (can't inject at the beginning because of `"use strict";`). // This is a short-term solution, and we hope to provide built-in polyfills like `node.__filename` on Rspack side. -export const pluginCjsShim = (): RsbuildPlugin => ({ +export const pluginCjsImportMetaUrlShim = (): RsbuildPlugin => ({ name: 'rsbuild-plugin-cjs-shim', - setup(api) { api.modifyEnvironmentConfig((config) => { config.source.define = { @@ -23,3 +22,26 @@ export const pluginCjsShim = (): RsbuildPlugin => ({ }); }, }); + +const requireShim = `// Rslib ESM shims +import __rslib_shim_module__ from 'module'; +const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(import.meta.url); +`; + +export const pluginEsmRequireShim = (): RsbuildPlugin => ({ + name: 'rsbuild-plugin-esm-shim', + setup(api) { + api.modifyRspackConfig((config) => { + config.plugins ??= []; + config.plugins.push( + new rspack.BannerPlugin({ + banner: requireShim, + // Just before minify stage, to perform tree shaking. + stage: rspack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE - 1, + raw: true, + include: /\.(js|cjs)$/, + }), + ); + }); + }, +}); diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index 2992aa67..f6749e85 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -48,6 +48,26 @@ export type BannerAndFooter = { dts?: string; }; +export type Shims = { + cjs?: + | boolean + | { + 'import.meta.url'?: boolean; + }; + esm?: + | boolean + | { + __filename?: boolean; + __dirname?: boolean; + require?: boolean; + }; +}; + +export type ResolvedShims = { + cjs: Required>>; + esm: Required>>; +}; + export type Redirect = { // TODO: support other redirects // alias?: boolean; @@ -67,6 +87,7 @@ export interface LibConfig extends RsbuildConfig { externalHelpers?: boolean; banner?: BannerAndFooter; footer?: BannerAndFooter; + shims?: Shims; dts?: Dts; } diff --git a/packages/core/tests/__snapshots__/config.test.ts.snap b/packages/core/tests/__snapshots__/config.test.ts.snap index 9aebb293..58541848 100644 --- a/packages/core/tests/__snapshots__/config.test.ts.snap +++ b/packages/core/tests/__snapshots__/config.test.ts.snap @@ -48,6 +48,7 @@ exports[`Should compose create Rsbuild config correctly > Merge Rsbuild config 1 "not dead", ], }, + "plugins": [], "source": { "alias": { "bar": "bar", @@ -110,6 +111,10 @@ exports[`Should compose create Rsbuild config correctly > Merge Rsbuild config 1 }, }, }, + "node": { + "__dirname": "node-module", + "__filename": "node-module", + }, "optimization": { "concatenateModules": true, "sideEffects": "flag", diff --git a/tests/benchmark/index.bench.ts b/tests/benchmark/index.bench.ts index ebd1743f..1d33cd11 100644 --- a/tests/benchmark/index.bench.ts +++ b/tests/benchmark/index.bench.ts @@ -6,7 +6,7 @@ describe('run rslib in examples', () => { 'examples/express-plugin', async () => { const cwd = getCwdByExample('express-plugin'); - await rslibBuild(cwd); + await rslibBuild({ cwd }); }, { time: 5 }, ); @@ -14,7 +14,7 @@ describe('run rslib in examples', () => { 'examples/react-component-bundle', async () => { const cwd = getCwdByExample('react-component-bundle'); - await rslibBuild(cwd); + await rslibBuild({ cwd }); }, { time: 5 }, ); @@ -22,7 +22,7 @@ describe('run rslib in examples', () => { 'examples/react-component-bundle-false', async () => { const cwd = getCwdByExample('react-component-bundle-false'); - await rslibBuild(cwd); + await rslibBuild({ cwd }); }, { time: 5 }, ); diff --git a/tests/integration/alias/index.test.ts b/tests/integration/alias/index.test.ts index fecdc4e3..c07d1869 100644 --- a/tests/integration/alias/index.test.ts +++ b/tests/integration/alias/index.test.ts @@ -3,7 +3,7 @@ import { expect, test } from 'vitest'; test('source.alias', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toContain('hello world'); expect(entries.cjs).toContain('hello world'); diff --git a/tests/integration/asset/index.test.ts b/tests/integration/asset/index.test.ts index 65cd85ea..6bc313b2 100644 --- a/tests/integration/asset/index.test.ts +++ b/tests/integration/asset/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('set the size threshold to inline static assets', async () => { const fixturePath = join(__dirname, 'limit'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // inline when bundle expect(Object.values(contents.esm0!)[0]).toContain( @@ -29,7 +29,7 @@ test('set the size threshold to inline static assets', async () => { test('set the assets name', async () => { const fixturePath = join(__dirname, 'name'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // bundle expect(Object.values(contents.esm0!)[0]).toContain( @@ -44,7 +44,7 @@ test('set the assets name', async () => { test('set the assets output path', async () => { const fixturePath = join(__dirname, 'path'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // bundle expect(Object.values(contents.esm0!)[0]).toContain( @@ -59,7 +59,7 @@ test('set the assets output path', async () => { test('set the assets public path', async () => { const fixturePath = join(__dirname, 'public-path'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // bundle expect(Object.values(contents.esm0!)[0]).toContain( @@ -74,7 +74,7 @@ test('set the assets public path', async () => { test('use svgr', async () => { const fixturePath = join(__dirname, 'svgr'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // bundle -- default export with react query expect(Object.values(contents.esm0!)[0]).toMatchSnapshot(); diff --git a/tests/integration/async-chunks/index.test.ts b/tests/integration/async-chunks/index.test.ts index c4202e66..d1e1e4fd 100644 --- a/tests/integration/async-chunks/index.test.ts +++ b/tests/integration/async-chunks/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should get correct value from async chunks', async () => { const fixturePath = join(__dirname, 'default'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); for (const format of ['esm', 'cjs']) { const { foo } = await import(entryFiles[format]); diff --git a/tests/integration/auto-extension/index.test.ts b/tests/integration/auto-extension/index.test.ts index 3efc43e4..84cd2124 100644 --- a/tests/integration/auto-extension/index.test.ts +++ b/tests/integration/auto-extension/index.test.ts @@ -5,14 +5,14 @@ import { describe, expect, test } from 'vitest'; describe('autoExtension: true', () => { test('generate .mjs in build artifacts with esm format when type is commonjs', async () => { const fixturePath = join(__dirname, 'type-commonjs', 'default'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(extname(entryFiles.esm!)).toEqual('.mjs'); expect(extname(entryFiles.cjs!)).toEqual('.js'); }); test('generate .cjs in build artifacts with cjs format when type is module', async () => { const fixturePath = join(__dirname, 'type-module', 'default'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(extname(entryFiles.esm!)).toEqual('.js'); expect(extname(entryFiles.cjs!)).toEqual('.cjs'); }); @@ -21,14 +21,14 @@ describe('autoExtension: true', () => { describe('autoExtension: false', () => { test('generate .js in both cjs and esm build artifacts when type is commonjs', async () => { const fixturePath = join(__dirname, 'type-commonjs', 'false'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(extname(entryFiles.esm!)).toEqual('.js'); expect(extname(entryFiles.cjs!)).toEqual('.js'); }); test('generate .js in both cjs and esm build artifacts when type is module', async () => { const fixturePath = join(__dirname, 'type-module', 'false'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(extname(entryFiles.esm!)).toEqual('.js'); expect(extname(entryFiles.cjs!)).toEqual('.js'); }); @@ -37,7 +37,7 @@ describe('autoExtension: false', () => { describe('should respect output.filename.js to override builtin logic', () => { test('type is commonjs', async () => { const fixturePath = join(__dirname, 'type-commonjs', 'config-override'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(extname(entryFiles.esm!)).toEqual('.mjs'); expect(entryFiles.cjs).toMatchInlineSnapshot( `"/tests/integration/auto-extension/type-commonjs/config-override/dist/cjs/index.d08e1bb3.js"`, @@ -46,7 +46,7 @@ describe('should respect output.filename.js to override builtin logic', () => { test('type is module', async () => { const fixturePath = join(__dirname, 'type-module', 'config-override'); - const { entryFiles } = await buildAndGetResults(fixturePath); + const { entryFiles } = await buildAndGetResults({ fixturePath }); expect(entryFiles.esm).toMatchInlineSnapshot( `"/tests/integration/auto-extension/type-module/config-override/dist/esm/index.d2068839.js"`, ); diff --git a/tests/integration/auto-external/index.test.ts b/tests/integration/auto-external/index.test.ts index c581e89c..21706b45 100644 --- a/tests/integration/auto-external/index.test.ts +++ b/tests/integration/auto-external/index.test.ts @@ -6,7 +6,7 @@ import { composeModuleImportWarn } from '../../../packages/core/src/config'; test('auto external default should works', async () => { const fixturePath = join(__dirname, 'default'); - const { js, dts } = await buildAndGetResults(fixturePath, 'all'); + const { js, dts } = await buildAndGetResults({ fixturePath, type: 'all' }); expect(js.entries.esm).toContain( 'import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react"', @@ -23,7 +23,7 @@ test('auto external default should works', async () => { test('auto external sub path should works', async () => { const fixturePath = join(__dirname, 'external-sub-path'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toContain( 'import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react"', @@ -42,7 +42,7 @@ test('auto external sub path should works', async () => { test('auto external false should works', async () => { const fixturePath = join(__dirname, 'false'); - const { js, dts } = await buildAndGetResults(fixturePath, 'all'); + const { js, dts } = await buildAndGetResults({ fixturePath, type: 'all' }); expect(js.entries.esm).not.toContain( 'import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react"', @@ -59,7 +59,7 @@ test('auto external false should works', async () => { test('externals should overrides auto external', async () => { const fixturePath = join(__dirname, 'with-externals'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toContain( 'import * as __WEBPACK_EXTERNAL_MODULE_react1__ from "react1"', @@ -73,7 +73,7 @@ test('externals should overrides auto external', async () => { test('should get warn when use require in ESM', async () => { const { logs, restore } = proxyConsole(); const fixturePath = join(__dirname, 'module-import-warn'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const logStrings = logs.map((log) => stripAnsi(log)); expect(entries.esm).toContain( diff --git a/tests/integration/banner-footer/index.test.ts b/tests/integration/banner-footer/index.test.ts index 52abef4f..4c9f7cd0 100644 --- a/tests/integration/banner-footer/index.test.ts +++ b/tests/integration/banner-footer/index.test.ts @@ -12,7 +12,10 @@ enum BannerFooter { test('banner and footer should work in js, css and dts', async () => { const fixturePath = __dirname; - const { js, css, dts } = await buildAndGetResults(fixturePath, 'all'); + const { js, css, dts } = await buildAndGetResults({ + fixturePath, + type: 'all', + }); const jsContents = Object.values(js.contents); const cssContents = Object.values(css.contents); diff --git a/tests/integration/bundle-false/index.test.ts b/tests/integration/bundle-false/index.test.ts index 25feec20..32e1d7cc 100644 --- a/tests/integration/bundle-false/index.test.ts +++ b/tests/integration/bundle-false/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('basic', async () => { const fixturePath = join(__dirname, 'basic'); - const { files } = await buildAndGetResults(fixturePath); + const { files } = await buildAndGetResults({ fixturePath }); expect(files.esm).toMatchInlineSnapshot(` [ @@ -26,7 +26,7 @@ test('basic', async () => { test('single file', async () => { const fixturePath = join(__dirname, 'single-file'); - const { files } = await buildAndGetResults(fixturePath); + const { files } = await buildAndGetResults({ fixturePath }); expect(files.esm).toMatchInlineSnapshot(` [ @@ -42,7 +42,7 @@ test('single file', async () => { test('auto add js extension for relative import', async () => { const fixturePath = join(__dirname, 'js-extension'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); for (const importer of [ 'import * as __WEBPACK_EXTERNAL_MODULE__bar_js__ from "./bar.js";', @@ -65,7 +65,7 @@ test('auto add js extension for relative import', async () => { test('asset in bundleless', async () => { const fixturePath = join(__dirname, 'asset'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); const assets = [ 'const image_namespaceObject = __webpack_require__.p + "static/image/image.png";', @@ -80,7 +80,7 @@ test('asset in bundleless', async () => { test('svgr in bundleless', async () => { const fixturePath = join(__dirname, 'svgr'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); // TODO: import "react"; in output now, we should shake this expect(Object.values(contents.esm)[0]).toMatchSnapshot(); diff --git a/tests/integration/copy/index.test.ts b/tests/integration/copy/index.test.ts index 0ac14864..a69390a2 100644 --- a/tests/integration/copy/index.test.ts +++ b/tests/integration/copy/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('copy', async () => { const fixturePath = __dirname; - await buildAndGetResults(fixturePath); + await buildAndGetResults({ fixturePath }); const fileTree = generateFileTree(join(fixturePath, './dist/esm')); expect(fileTree).toMatchInlineSnapshot(` diff --git a/tests/integration/decorators/index.test.ts b/tests/integration/decorators/index.test.ts index cc3c72e4..c325e251 100644 --- a/tests/integration/decorators/index.test.ts +++ b/tests/integration/decorators/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('decorators default to 2022-03', async () => { const fixturePath = join(__dirname, 'default'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); // use 2022-03 decorator by default expect(entries.esm).toMatchSnapshot(); @@ -12,7 +12,7 @@ test('decorators default to 2022-03', async () => { test('decorators with experimentalDecorators in tsconfig', async () => { const fixturePath = join(__dirname, 'tsconfig'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); // use legacy decorator when experimentalDecorators in tsconfig expect(entries.esm0).toMatchSnapshot(); diff --git a/tests/integration/define/index.test.ts b/tests/integration/define/index.test.ts index 7363f245..5a2daa54 100644 --- a/tests/integration/define/index.test.ts +++ b/tests/integration/define/index.test.ts @@ -3,7 +3,7 @@ import { expect, test } from 'vitest'; test('source.define', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm0).not.toContain('console.info(VERSION)'); expect(entries.esm0).toContain('console.info("1.0.0")'); diff --git a/tests/integration/dts/index.test.ts b/tests/integration/dts/index.test.ts index 1897a227..d5c04a02 100644 --- a/tests/integration/dts/index.test.ts +++ b/tests/integration/dts/index.test.ts @@ -5,7 +5,10 @@ import { describe, expect, test } from 'vitest'; describe('dts when bundle: false', () => { test('basic', async () => { const fixturePath = join(__dirname, 'bundle-false', 'basic'); - const { files, contents } = await buildAndGetResults(fixturePath, 'dts'); + const { files, contents } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(files.esm).toMatchInlineSnapshot(` [ @@ -30,14 +33,14 @@ describe('dts when bundle: false', () => { test('dts false', async () => { const fixturePath = join(__dirname, 'bundle-false', 'false'); - const { files } = await buildAndGetResults(fixturePath, 'dts'); + const { files } = await buildAndGetResults({ fixturePath, type: 'dts' }); expect(files.esm).toMatchInlineSnapshot('undefined'); }); test('distPath', async () => { const fixturePath = join(__dirname, 'bundle-false', 'dist-path'); - const { files } = await buildAndGetResults(fixturePath, 'dts'); + const { files } = await buildAndGetResults({ fixturePath, type: 'dts' }); expect(files.esm).toMatchInlineSnapshot(` [ @@ -51,14 +54,17 @@ describe('dts when bundle: false', () => { test('abortOnError: false', async () => { const fixturePath = join(__dirname, 'bundle-false', 'abort-on-error'); - const { isSuccess } = await buildAndGetResults(fixturePath, 'dts'); + const { isSuccess } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(isSuccess).toBe(true); }); test('autoExtension: true', async () => { const fixturePath = join(__dirname, 'bundle-false', 'auto-extension'); - const { files } = await buildAndGetResults(fixturePath, 'dts'); + const { files } = await buildAndGetResults({ fixturePath, type: 'dts' }); expect(files.cjs).toMatchInlineSnapshot(` [ @@ -74,10 +80,10 @@ describe('dts when bundle: false', () => { describe('dts when bundle: true', () => { test('basic', async () => { const fixturePath = join(__dirname, 'bundle', 'basic'); - const { entryFiles, entries } = await buildAndGetResults( + const { entryFiles, entries } = await buildAndGetResults({ fixturePath, - 'dts', - ); + type: 'dts', + }); expect(entryFiles.esm).toMatchInlineSnapshot( `"/tests/integration/dts/bundle/basic/dist/esm/index.d.ts"`, @@ -92,14 +98,20 @@ describe('dts when bundle: true', () => { test('dts false', async () => { const fixturePath = join(__dirname, 'bundle', 'false'); - const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + const { entryFiles } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(entryFiles.esm).toMatchInlineSnapshot('undefined'); }); test('distPath', async () => { const fixturePath = join(__dirname, 'bundle', 'dist-path'); - const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + const { entryFiles } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(entryFiles.esm).toMatchInlineSnapshot( `"/tests/integration/dts/bundle/dist-path/dist/custom/index.d.ts"`, @@ -108,14 +120,20 @@ describe('dts when bundle: true', () => { test('abortOnError: false', async () => { const fixturePath = join(__dirname, 'bundle', 'abort-on-error'); - const { isSuccess } = await buildAndGetResults(fixturePath, 'dts'); + const { isSuccess } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(isSuccess).toBe(true); }); test('autoExtension: true', async () => { const fixturePath = join(__dirname, 'bundle', 'auto-extension'); - const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + const { entryFiles } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(entryFiles.cjs).toMatchInlineSnapshot( `"/tests/integration/dts/bundle/auto-extension/dist/cjs/index.d.cts"`, @@ -124,7 +142,10 @@ describe('dts when bundle: true', () => { test('bundleName -- set source.entry', async () => { const fixturePath = join(__dirname, 'bundle', 'bundle-name'); - const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + const { entryFiles } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(entryFiles.esm).toMatchInlineSnapshot( `"/tests/integration/dts/bundle/bundle-name/dist/esm/bundleName.d.ts"`, @@ -133,7 +154,10 @@ describe('dts when bundle: true', () => { test('entry is an absolute path', async () => { const fixturePath = join(__dirname, 'bundle', 'absolute-entry'); - const { entryFiles } = await buildAndGetResults(fixturePath, 'dts'); + const { entryFiles } = await buildAndGetResults({ + fixturePath, + type: 'dts', + }); expect(entryFiles.esm).toMatchInlineSnapshot( `"/tests/integration/dts/bundle/absolute-entry/dist/esm/index.d.ts"`, diff --git a/tests/integration/entry/index.test.ts b/tests/integration/entry/index.test.ts index 43360678..97ccdd1b 100644 --- a/tests/integration/entry/index.test.ts +++ b/tests/integration/entry/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('single entry bundle', async () => { const fixturePath = join(__dirname, 'single'); - const { files } = await buildAndGetResults(fixturePath); + const { files } = await buildAndGetResults({ fixturePath }); expect(files).toMatchInlineSnapshot(` { @@ -20,7 +20,7 @@ test('single entry bundle', async () => { test('multiple entry bundle', async () => { const fixturePath = join(__dirname, 'multiple'); - const { files } = await buildAndGetResults(fixturePath); + const { files } = await buildAndGetResults({ fixturePath }); expect(files).toMatchInlineSnapshot(` { @@ -38,7 +38,7 @@ test('multiple entry bundle', async () => { test('glob entry bundleless', async () => { const fixturePath = join(__dirname, 'glob'); - const { files } = await buildAndGetResults(fixturePath); + const { files } = await buildAndGetResults({ fixturePath }); expect(files).toMatchInlineSnapshot(` { diff --git a/tests/integration/extension-alias/index.test.ts b/tests/integration/extension-alias/index.test.ts index 32f24115..b628ca8f 100644 --- a/tests/integration/extension-alias/index.test.ts +++ b/tests/integration/extension-alias/index.test.ts @@ -3,7 +3,7 @@ import { expect, test } from 'vitest'; test('resolve.extensionAlias should work', async () => { const fixturePath = __dirname; - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.cjs).toMatchSnapshot(); expect(entries.esm).toMatchSnapshot(); diff --git a/tests/integration/external-helpers/index.test.ts b/tests/integration/external-helpers/index.test.ts index ac0f733e..2a18a45b 100644 --- a/tests/integration/external-helpers/index.test.ts +++ b/tests/integration/external-helpers/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should not external @swc/helpers by default', async () => { const fixturePath = join(__dirname, 'default'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toMatchSnapshot(); }); @@ -15,7 +15,7 @@ test('should throw error when @swc/helpers is not be installed when externalHelp const fixturePath = join(__dirname, 'no-deps'); try { - await buildAndGetResults(fixturePath); + await buildAndGetResults({ fixturePath }); } catch {} const logStrings = logs.map((log) => stripAnsi(log)); @@ -31,7 +31,7 @@ test('should throw error when @swc/helpers is not be installed when externalHelp test('should external @swc/helpers when externalHelpers is true', async () => { const fixturePath = join(__dirname, 'true'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); // autoExternal is true expect(entries.esm0).toMatchSnapshot(); @@ -41,7 +41,7 @@ test('should external @swc/helpers when externalHelpers is true', async () => { test('should respect user override externalHelpers config', async () => { const fixturePath = join(__dirname, 'config-override'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); // override externalHelpers false expect(entries.esm0).toMatchSnapshot(); diff --git a/tests/integration/externals/index.test.ts b/tests/integration/externals/index.test.ts index 6fed5428..8e0fe292 100644 --- a/tests/integration/externals/index.test.ts +++ b/tests/integration/externals/index.test.ts @@ -6,13 +6,13 @@ import { composeModuleImportWarn } from '../../../packages/core/src/config'; test('should fail to build when `output.target` is not "node"', async () => { const fixturePath = join(__dirname, 'browser'); - const build = buildAndGetResults(fixturePath); + const build = buildAndGetResults({ fixturePath }); await expect(build).rejects.toThrowError('Rspack build failed!'); }); test('auto externalize Node.js built-in modules when `output.target` is "node"', async () => { const fixturePath = join(__dirname, 'node'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); for (const external of [ 'import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs"', @@ -38,7 +38,7 @@ test('auto externalize Node.js built-in modules when `output.target` is "node"', test('should get warn when use require in ESM', async () => { const { logs, restore } = proxyConsole(); const fixturePath = join(__dirname, 'module-import-warn'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const logStrings = logs.map((log) => stripAnsi(log)); for (const external of [ diff --git a/tests/integration/minify/index.test.ts b/tests/integration/minify/index.test.ts index 0e51e82e..73baeb9f 100644 --- a/tests/integration/minify/index.test.ts +++ b/tests/integration/minify/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('tree shaking is enabled by default, bar and baz should be shaken', async () => { const fixturePath = join(__dirname, 'default'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toMatchInlineSnapshot(` "const foo = ()=>{}; export { foo }; diff --git a/tests/integration/require/index.test.ts b/tests/integration/require/index.test.ts index b64d4356..c7c58014 100644 --- a/tests/integration/require/index.test.ts +++ b/tests/integration/require/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('require.resolve', async () => { const fixturePath = join(__dirname, 'require-resolve'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const statements = [ "const cjs1 = require.resolve('./other')", @@ -37,7 +37,7 @@ test('require.resolve', async () => { test('require dynamic', async () => { const fixturePath = join(__dirname, 'require-dynamic'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const statements = [ 'const cjs1 = require(`${process.env.DIR}./other`)', @@ -66,7 +66,7 @@ test('require dynamic', async () => { test('import dynamic', async () => { const fixturePath = join(__dirname, 'import-dynamic'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const statements = [ 'const i1 = import(`${process.env.DIR}./other`)', @@ -85,7 +85,7 @@ test('import dynamic', async () => { test('require as expression', async () => { const fixturePath = join(__dirname, 'require-as-expression'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); const statements = [ 'const lazyFn = (module, requireFn)=>{}', diff --git a/tests/integration/require/require-resolve/other.ts b/tests/integration/require/require-resolve/other.ts new file mode 100644 index 00000000..46c7130a --- /dev/null +++ b/tests/integration/require/require-resolve/other.ts @@ -0,0 +1 @@ +module.exports = 'ok'; diff --git a/tests/integration/resolve/index.test.ts b/tests/integration/resolve/index.test.ts index 0cbd76e7..57213cd2 100644 --- a/tests/integration/resolve/index.test.ts +++ b/tests/integration/resolve/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('resolve data url', async () => { const fixturePath = join(__dirname, 'data-url'); - const { entries, isSuccess } = await buildAndGetResults(fixturePath); + const { entries, isSuccess } = await buildAndGetResults({ fixturePath }); expect(isSuccess).toBeTruthy(); expect(entries.esm).toMatchInlineSnapshot(` @@ -18,7 +18,7 @@ test('resolve data url', async () => { // EXTERNAL MODULE: /rslib/e2e/cases/resolve/false/./browser-false/util (ignored) test.todo('resolve false', async () => { const fixturePath = join(__dirname, 'false'); - const { entries, isSuccess } = await buildAndGetResults(fixturePath); + const { entries, isSuccess } = await buildAndGetResults({ fixturePath }); expect(isSuccess).toBeTruthy(); expect(entries.esm).toMatchSnapshot(); @@ -26,7 +26,7 @@ test.todo('resolve false', async () => { test('resolve node protocol', async () => { const fixturePath = join(__dirname, 'node-protocol'); - const { entries, isSuccess } = await buildAndGetResults(fixturePath); + const { entries, isSuccess } = await buildAndGetResults({ fixturePath }); expect(isSuccess).toBeTruthy(); expect(entries.esm).toMatchInlineSnapshot(` @@ -39,7 +39,7 @@ test('resolve node protocol', async () => { test('resolve with condition exports', async () => { const fixturePath = join(__dirname, 'with-condition-exports'); - const { contents, isSuccess } = await buildAndGetResults(fixturePath); + const { contents, isSuccess } = await buildAndGetResults({ fixturePath }); const nodeResults = Object.values(contents.esm0!); const browserResults = Object.values(contents.esm1!); @@ -59,7 +59,7 @@ test('resolve with condition exports', async () => { test('resolve with js extensions', async () => { const fixturePath = join(__dirname, 'with-js-extensions'); - const { entries, isSuccess } = await buildAndGetResults(fixturePath); + const { entries, isSuccess } = await buildAndGetResults({ fixturePath }); expect(isSuccess).toBeTruthy(); expect(entries.esm).toMatchInlineSnapshot(` @@ -71,7 +71,7 @@ test('resolve with js extensions', async () => { test('resolve with main fields', async () => { const fixturePath = join(__dirname, 'with-main-fields'); - const { contents, isSuccess } = await buildAndGetResults(fixturePath); + const { contents, isSuccess } = await buildAndGetResults({ fixturePath }); const results = Object.values(contents); expect(isSuccess).toBeTruthy(); diff --git a/tests/integration/shims/cjs/rslib.config.ts b/tests/integration/shims/cjs/rslib.config.ts index 3db5c5e1..18492bfa 100644 --- a/tests/integration/shims/cjs/rslib.config.ts +++ b/tests/integration/shims/cjs/rslib.config.ts @@ -2,7 +2,14 @@ import { defineConfig } from '@rslib/core'; import { generateBundleCjsConfig, generateBundleEsmConfig } from 'test-helper'; export default defineConfig({ - lib: [generateBundleEsmConfig(), generateBundleCjsConfig()], + lib: [ + generateBundleEsmConfig(), + generateBundleCjsConfig({ + shims: { + cjs: true, + }, + }), + ], output: { target: 'node', copy: [{ from: 'src/ok.cjs' }], diff --git a/tests/integration/shims/cjs/src/index.ts b/tests/integration/shims/cjs/src/index.ts index b96bf28a..7695d129 100644 --- a/tests/integration/shims/cjs/src/index.ts +++ b/tests/integration/shims/cjs/src/index.ts @@ -1,3 +1,4 @@ +// import.meta.url import { createRequire } from 'node:module'; const importMetaUrl = import.meta.url; const require = createRequire(import.meta.url); diff --git a/tests/integration/shims/esm/rslib.config.ts b/tests/integration/shims/esm/rslib.config.ts index 8aebc6bb..3ff50b22 100644 --- a/tests/integration/shims/esm/rslib.config.ts +++ b/tests/integration/shims/esm/rslib.config.ts @@ -4,17 +4,44 @@ import { generateBundleEsmConfig } from 'test-helper'; export default defineConfig({ lib: [ generateBundleEsmConfig({ + shims: { esm: true }, + source: { + entry: { + index: './src/index.ts', + }, + }, + output: { + distPath: { + root: './dist/enabled/esm0', + }, + }, + }), + generateBundleEsmConfig({ + shims: { esm: true }, + syntax: 'esnext', + source: { + entry: { + index: './src/index.ts', + }, + }, output: { distPath: { - root: './dist/normal', + root: './dist/enabled/esm1', }, }, }), generateBundleEsmConfig({ + shims: { esm: true }, syntax: 'esnext', + source: { + entry: { + index: './src/require.ts', + }, + }, output: { + copy: [{ from: './src/ok.cjs' }], distPath: { - root: './dist/with-syntax', + root: './dist/enabled/esm2', }, }, }), @@ -22,9 +49,4 @@ export default defineConfig({ output: { target: 'node', }, - source: { - entry: { - index: './src/index.ts', - }, - }, }); diff --git a/tests/integration/shims/esm/rslibShimsDisabled.config.ts b/tests/integration/shims/esm/rslibShimsDisabled.config.ts new file mode 100644 index 00000000..e036a5cf --- /dev/null +++ b/tests/integration/shims/esm/rslibShimsDisabled.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from '@rslib/core'; +import config from './rslib.config'; + +export default defineConfig({ + ...config, + lib: [config.lib[2]!].map((libConfig) => { + libConfig.output!.distPath!.root = + libConfig.output!.distPath!.root!.replace( + './dist/enabled', + './dist/disabled', + ); + delete libConfig.shims; + return libConfig; + }), +}); diff --git a/tests/integration/shims/esm/src/index.ts b/tests/integration/shims/esm/src/index.ts index a58d453f..a017795c 100644 --- a/tests/integration/shims/esm/src/index.ts +++ b/tests/integration/shims/esm/src/index.ts @@ -1,7 +1,8 @@ -export const foo = () => { - const d1 = __dirname; +const d1 = __dirname; +const f1 = __filename; + +export default () => { const d2 = __dirname; - const f1 = __filename; const f2 = __filename; const importMetaUrl = import.meta.url; diff --git a/tests/integration/shims/esm/src/ok.cjs b/tests/integration/shims/esm/src/ok.cjs new file mode 100644 index 00000000..46c7130a --- /dev/null +++ b/tests/integration/shims/esm/src/ok.cjs @@ -0,0 +1 @@ +module.exports = 'ok'; diff --git a/tests/integration/shims/esm/src/require.ts b/tests/integration/shims/esm/src/require.ts new file mode 100644 index 00000000..d45cad7f --- /dev/null +++ b/tests/integration/shims/esm/src/require.ts @@ -0,0 +1,4 @@ +const ok = require != null && require('./ok.cjs'); +const okPath = require.resolve('./ok.cjs'); + +export { ok, okPath }; diff --git a/tests/integration/shims/index.test.ts b/tests/integration/shims/index.test.ts index 365bb672..6b7e1687 100644 --- a/tests/integration/shims/index.test.ts +++ b/tests/integration/shims/index.test.ts @@ -1,29 +1,84 @@ -import { join } from 'node:path'; +import path, { join } from 'node:path'; import { pathToFileURL } from 'node:url'; import vm from 'node:vm'; import { buildAndGetResults } from 'test-helper'; import { describe, expect, test } from 'vitest'; -test('shims for __dirname and __filename in ESM', async () => { +describe('ESM shims', async () => { const fixturePath = join(__dirname, 'esm'); - const { entries } = await buildAndGetResults(fixturePath); - - for (const shim of [ - 'import { fileURLToPath as __webpack_fileURLToPath__ } from "url";', - 'var src_dirname = __webpack_dirname__(__webpack_fileURLToPath__(import.meta.url));', - 'var src_filename = __webpack_fileURLToPath__(import.meta.url);', - // import.meta.url should not be substituted - 'const importMetaUrl = import.meta.url;', - ]) { - expect(entries.esm0).toContain(shim); - } - expect(entries.esm0).toBe(entries.esm1); + const { entries, entryFiles } = await buildAndGetResults({ fixturePath }); + const entry0Result = (await import(entryFiles.esm0!)).default(); + + test('__dirname', async () => { + for (const shim of [ + 'import { fileURLToPath as __webpack_fileURLToPath__ } from "url";', + 'var src_dirname = __webpack_dirname__(__webpack_fileURLToPath__(import.meta.url));', + ]) { + expect(entries.esm0).toContain(shim); + } + expect(entry0Result.d1).toBe(path.dirname(entryFiles.esm0!)); + expect(entry0Result.d1).toBe(entry0Result.d2); + + expect(entries.esm0).toBe(entries.esm1); + }); + + test('__filename', async () => { + for (const shim of [ + 'import { fileURLToPath as __webpack_fileURLToPath__ } from "url";', + 'var src_filename = __webpack_fileURLToPath__(import.meta.url);', + ]) { + expect(entries.esm0).toContain(shim); + } + expect(entry0Result.f1).toBe(entryFiles.esm0); + expect(entry0Result.f1).toBe(entry0Result.f2); + + expect(entries.esm0).toBe(entries.esm1); + }); + + test('import.meta.url', async () => { + for (const shouldPreserve of [ + // import.meta.url should not be substituted + 'const importMetaUrl = import.meta.url;', + ]) { + expect(entries.esm0).toContain(shouldPreserve); + } + expect(entry0Result.importMetaUrl).toBe( + pathToFileURL(entryFiles.esm0!).href, + ); + }); + + test('require', async () => { + const { ok, okPath } = await import(entryFiles.esm2!); + expect(ok).toBe('ok'); + expect(okPath).toBe(path.resolve(path.dirname(entryFiles.esm2!), 'ok.cjs')); + }); +}); + +describe('ESM shims disabled', async () => { + test('using require in ESM without shim will cause runtime error', async () => { + const fixturePath = join(__dirname, 'esm'); + const { entries } = await buildAndGetResults({ + fixturePath, + configPath: './rslibShimsDisabled.config.ts', + }); + const context = vm.createContext({}); + const module = new vm.SourceTextModule(entries.esm, { + context, + }); + + const linker: vm.ModuleLinker = async (specifier) => { + throw new Error(`Unable to resolve dependency: ${specifier}`); + }; + + await module.link(linker); + await expect(module.evaluate()).rejects.toThrow('require is not defined'); + }); }); -describe('shims for `import.meta.url` in CJS', () => { - test('CJS should apply shims', async () => { +describe('CJS shims', () => { + test('import.meta.url', async () => { const fixturePath = join(__dirname, 'cjs'); - const { entryFiles, entries } = await buildAndGetResults(fixturePath); + const { entryFiles, entries } = await buildAndGetResults({ fixturePath }); // `module.require` is not available in Vitest runner context. Manually create a context to run the CJS code. // As a temporary solution, we use `module.require` to avoid potential collision with module scope variable `require`. const cjsCode = entries.cjs; @@ -41,9 +96,10 @@ describe('shims for `import.meta.url` in CJS', () => { test('ESM should not be affected by CJS shims configuration', async () => { const fixturePath = join(__dirname, 'cjs'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toMatchInlineSnapshot(` "import * as __WEBPACK_EXTERNAL_MODULE_node_module__ from \\"node:module\\"; + // import.meta.url const importMetaUrl = import.meta.url; const src_require = (0, __WEBPACK_EXTERNAL_MODULE_node_module__.createRequire)(import.meta.url); const requiredModule = src_require('./ok.cjs'); diff --git a/tests/integration/sourcemap/index.test.ts b/tests/integration/sourcemap/index.test.ts index 1d9cb92d..7ddc464b 100644 --- a/tests/integration/sourcemap/index.test.ts +++ b/tests/integration/sourcemap/index.test.ts @@ -1,11 +1,10 @@ -import os from 'node:os'; import { join } from 'node:path'; import { buildAndGetResults } from 'test-helper'; import { expect, test } from 'vitest'; test('should not generate js sourcemap by default', async () => { const fixturePath = join(__dirname, 'default'); - const { contents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath }); const files = Object.keys(contents.esm); expect(files).toMatchInlineSnapshot(` @@ -17,7 +16,7 @@ test('should not generate js sourcemap by default', async () => { test('should generate js external sourcemap: cheap-module-source-map', async () => { const fixturePath = join(__dirname, 'external'); - const { contents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath }); const files = Object.keys(contents.esm); expect(files).toMatchInlineSnapshot(` @@ -30,7 +29,7 @@ test('should generate js external sourcemap: cheap-module-source-map', async () test('should generate js inline sourcemap: inline-cheap-module-source-map', async () => { const fixturePath = join(__dirname, 'inline'); - const { contents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath }); const files = Object.keys(contents.esm); const code = Object.values(contents.esm); diff --git a/tests/integration/style/css-modules/index.test.ts b/tests/integration/style/css-modules/index.test.ts index 2a88a4d8..8ed2d036 100644 --- a/tests/integration/style/css-modules/index.test.ts +++ b/tests/integration/style/css-modules/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should extract css-modules successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` @@ -24,8 +24,8 @@ test('should extract css-modules successfully in bundle', async () => { test('should extract css-modules successfully in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); - const { contents: jsContents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); + const { contents: jsContents } = await buildAndGetResults({ fixturePath }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` @@ -56,8 +56,8 @@ test('should extract css-modules successfully in bundle-false', async () => { test('should extract css-modules successfully in bundle-false with output.cssModules.auto config', async () => { const fixturePath = join(__dirname, 'bundle-false-auto'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); - const { contents: jsContents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); + const { contents: jsContents } = await buildAndGetResults({ fixturePath }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` diff --git a/tests/integration/style/css/index.test.ts b/tests/integration/style/css/index.test.ts index b81d5673..e38ba0fd 100644 --- a/tests/integration/style/css/index.test.ts +++ b/tests/integration/style/css/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should extract css successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ @@ -22,7 +22,7 @@ test('should extract css successfully in bundle', async () => { test('should extract css successfully in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ diff --git a/tests/integration/style/less/index.test.ts b/tests/integration/style/less/index.test.ts index 0f80250a..7aa179e9 100644 --- a/tests/integration/style/less/index.test.ts +++ b/tests/integration/style/less/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should extract with pluginLess successfully in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` @@ -28,7 +28,7 @@ test('should extract with pluginLess successfully in bundle-false', async () => test('should extract css with pluginLess successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` @@ -47,7 +47,7 @@ test('should extract css with pluginLess successfully in bundle', async () => { test('should extract css with pluginLess successfully in import case', async () => { const fixturePath = join(__dirname, 'bundle-import'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` diff --git a/tests/integration/style/lightningcss/index.test.ts b/tests/integration/style/lightningcss/index.test.ts index 14728166..b4fdff35 100644 --- a/tests/integration/style/lightningcss/index.test.ts +++ b/tests/integration/style/lightningcss/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should extract css with lightningcss-loader successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ @@ -33,7 +33,7 @@ test('should extract css with lightningcss-loader successfully in bundle', async test('should extract css with lightningcss-loader successfully in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ diff --git a/tests/integration/style/postcss/index.test.ts b/tests/integration/style/postcss/index.test.ts index 00e9443c..8f5565f3 100644 --- a/tests/integration/style/postcss/index.test.ts +++ b/tests/integration/style/postcss/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should extract css with postcss-loader successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` @@ -26,7 +26,7 @@ test('should extract css with postcss-loader successfully in bundle', async () = test('should extract css with postcss-loader successfully in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` diff --git a/tests/integration/style/redirect-style-false/index.test.ts b/tests/integration/style/redirect-style-false/index.test.ts index b4268607..3961e1d5 100644 --- a/tests/integration/style/redirect-style-false/index.test.ts +++ b/tests/integration/style/redirect-style-false/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should extract css successfully when using redirect.style = false', async () => { const fixturePath = __dirname; - const { contents } = await buildAndGetResults(fixturePath, 'js'); + const { contents } = await buildAndGetResults({ fixturePath }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ diff --git a/tests/integration/style/sass/index.test.ts b/tests/integration/style/sass/index.test.ts index 207fc6b2..eddf06bc 100644 --- a/tests/integration/style/sass/index.test.ts +++ b/tests/integration/style/sass/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should extract css with pluginSass in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ @@ -22,7 +22,7 @@ test('should extract css with pluginSass in bundle', async () => { test('should extract css with pluginSass in bundle-false', async () => { const fixturePath = join(__dirname, 'bundle-false'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` diff --git a/tests/integration/style/style-inject/index.test.ts b/tests/integration/style/style-inject/index.test.ts index 535a2d29..238fa0fc 100644 --- a/tests/integration/style/style-inject/index.test.ts +++ b/tests/integration/style/style-inject/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should extract css successfully with `output.styleInject = true` in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm ?? {}); expect(esmFiles).toMatchInlineSnapshot('[]'); diff --git a/tests/integration/style/tailwindcss/index.test.ts b/tests/integration/style/tailwindcss/index.test.ts index 9b04b32b..989cb24c 100644 --- a/tests/integration/style/tailwindcss/index.test.ts +++ b/tests/integration/style/tailwindcss/index.test.ts @@ -5,7 +5,7 @@ import { expect, test } from 'vitest'; test('should extract css when using tailwindcss successfully in bundle', async () => { const fixturePath = join(__dirname, 'bundle'); - const { contents } = await buildAndGetResults(fixturePath, 'css'); + const { contents } = await buildAndGetResults({ fixturePath, type: 'css' }); const esmFiles = Object.keys(contents.esm); expect(esmFiles).toMatchInlineSnapshot(` [ diff --git a/tests/integration/syntax/index.test.ts b/tests/integration/syntax/index.test.ts index e59239f8..462a8bc5 100644 --- a/tests/integration/syntax/index.test.ts +++ b/tests/integration/syntax/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('should downgrade class private method by default', async () => { const fixturePath = join(__dirname, 'default'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm).toMatchSnapshot(); expect(entries.esm).toContain('#bar'); @@ -14,7 +14,7 @@ test('should downgrade class private method by default', async () => { test('should downgrade class private method with output.syntax config', async () => { const fixturePath = join(__dirname, 'config'); - const { entries } = await buildAndGetResults(fixturePath); + const { entries } = await buildAndGetResults({ fixturePath }); expect(entries.esm0).toMatchSnapshot(); expect(entries.esm0).not.toContain('#bar'); diff --git a/tests/integration/transform-import/index.test.ts b/tests/integration/transform-import/index.test.ts index d59d3b9a..349c41a2 100644 --- a/tests/integration/transform-import/index.test.ts +++ b/tests/integration/transform-import/index.test.ts @@ -4,7 +4,7 @@ import { expect, test } from 'vitest'; test('transformImport with arco-design', async () => { const fixturePath = join(__dirname, 'arco-design'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); const formats: FormatType[] = ['esm0', 'esm1', 'cjs0', 'cjs1']; for (const format of formats) { @@ -23,7 +23,7 @@ test('transformImport with arco-design', async () => { test('transformImport with lodash', async () => { const fixturePath = join(__dirname, 'lodash'); - const { contents } = await buildAndGetResults(fixturePath); + const { contents } = await buildAndGetResults({ fixturePath }); const formats: FormatType[] = ['esm0', 'esm1', 'cjs0', 'cjs1']; for (const format of formats) { diff --git a/tests/integration/tsconfig/index.test.ts b/tests/integration/tsconfig/index.test.ts index 7fa2ec9e..3db59acc 100644 --- a/tests/integration/tsconfig/index.test.ts +++ b/tests/integration/tsconfig/index.test.ts @@ -3,7 +3,7 @@ import { expect, test } from 'vitest'; test('tsconfig path', async () => { const fixturePath = __dirname; - const { isSuccess, entries } = await buildAndGetResults(fixturePath); + const { isSuccess, entries } = await buildAndGetResults({ fixturePath }); expect(isSuccess).toBe(true); expect(entries.esm).toContain(`const foo = 'foo'`); diff --git a/tests/scripts/shared.ts b/tests/scripts/shared.ts index 71e4b5d0..ef38f8f9 100644 --- a/tests/scripts/shared.ts +++ b/tests/scripts/shared.ts @@ -145,32 +145,46 @@ export async function getResults( }; } -export async function rslibBuild(fixturePath: string) { +export async function rslibBuild({ + cwd, + path, +}: { cwd: string; path?: string }) { const rslibConfig = await loadConfig({ - cwd: fixturePath, + cwd, + path, }); - process.chdir(fixturePath); + process.chdir(cwd); const rsbuildInstance = await build(rslibConfig); return { rsbuildInstance, rslibConfig }; } -export async function buildAndGetResults( - fixturePath: string, - type: 'all', -): Promise<{ +export async function buildAndGetResults(options: { + fixturePath: string; + configPath?: string; + type: 'all'; +}): Promise<{ js: BuildResult; dts: BuildResult; css: BuildResult; }>; -export async function buildAndGetResults( - fixturePath: string, - type?: 'js' | 'dts' | 'css', -): Promise; -export async function buildAndGetResults( - fixturePath: string, - type: 'js' | 'dts' | 'css' | 'all' = 'js', -) { - const { rsbuildInstance, rslibConfig } = await rslibBuild(fixturePath); +export async function buildAndGetResults(options: { + fixturePath: string; + configPath?: string; + type?: 'js' | 'dts' | 'css'; +}): Promise; +export async function buildAndGetResults({ + fixturePath, + configPath, + type = 'js', +}: { + fixturePath: string; + configPath?: string; + type?: 'js' | 'dts' | 'css' | 'all'; +}) { + const { rsbuildInstance, rslibConfig } = await rslibBuild({ + cwd: fixturePath, + path: configPath, + }); const { origin: { bundlerConfigs, rsbuildConfig }, } = await rsbuildInstance.inspectConfig({ verbose: true }); diff --git a/website/docs/en/_meta.json b/website/docs/en/_meta.json index d07f8a40..98867201 100644 --- a/website/docs/en/_meta.json +++ b/website/docs/en/_meta.json @@ -3,5 +3,10 @@ "text": "Guide", "link": "/guide/start/", "activeMatch": "/guide/" + }, + { + "text": "Config", + "link": "/config/", + "activeMatch": "/config/" } ] diff --git a/website/docs/en/config/_meta.json b/website/docs/en/config/_meta.json new file mode 100644 index 00000000..392f19b6 --- /dev/null +++ b/website/docs/en/config/_meta.json @@ -0,0 +1,12 @@ +[ + { + "type": "file", + "name": "index", + "label": "Overview" + }, + { + "type": "dir", + "name": "lib", + "label": "lib" + } + ] \ No newline at end of file diff --git a/website/docs/en/config/index.mdx b/website/docs/en/config/index.mdx new file mode 100644 index 00000000..2fdf3693 --- /dev/null +++ b/website/docs/en/config/index.mdx @@ -0,0 +1,3 @@ +# Config Overview + +This page lists all the configurations for Rslib. See ["Configure Rslib"](/guide/basic/configure-rslib) for detail. diff --git a/website/docs/en/config/lib/shims.mdx b/website/docs/en/config/lib/shims.mdx new file mode 100644 index 00000000..5064aa27 --- /dev/null +++ b/website/docs/en/config/lib/shims.mdx @@ -0,0 +1,164 @@ +# lib.shims + +- **Type:** + +```ts +type Shims = { + cjs?: + | boolean + | { + 'import.meta.url'?: boolean; + }; + esm?: + | boolean + | { + __filename?: boolean; + __dirname?: boolean; + require?: boolean; + }; +}; +``` + +- **Default:** + +```js +{ + cjs: { + 'import.meta.url': true, + }, + esm: { + __filename: true, + __dirname: true, + require: false, + }, +} +``` + +Used to configure the shims for CommonJS and ESM output. + +## shims.cjs + +- set to `true` to enable all shims for CommonJS output. +- set to `false` to disable all shims for CommonJS output. +- set the fields to `true` to enable the corresponding shims for CommonJS output. + +### shims.cjs['import.meta.url'] + +- **Default:** `true` + +Options: + +- `true`: when `format` is `cjs`, the `import.meta.url` in source code will be replaced with the URL of the current module. + + For example, given the following source code: + + ```js + import { readFileSync } from 'fs'; + const buffer = readFileSync(new URL('./data.proto', import.meta.url)); + ``` + + the CJS output will be transformed to: + + ```js + const { readFileSync } = require('fs'); + const buffer = readFileSync(new URL('./data.proto', /*#__PURE__*/ (function () { + return typeof document === 'undefined' + ? new (module.require('url'.replace('', '')).URL)('file:' + __filename).href + : (document.currentScript && document.currentScript.src) || + new URL('main.js', document.baseURI).href; + })())); + ``` + +- `false`: the `import.meta.url` will be leave as is, which will cause a runtime error when running the output. + +## shims.esm + +- set to `true` to enable all shims for ESM output. +- set to `false` to disable all shims for ESM output. +- set the fields to `true` to enable the corresponding shims for ESM output. + +### shims.esm.__filename + +- **Default:** `false` + +Options: + +- `true`: when `format` is `esm`, the `__filename` in source code will be replaced with the filename of the current module. + + For example, given the following source code: + + ```js + console.log(__filename); + ``` + + the ESM output will be transformed to: + + ```js + import { fileURLToPath as __webpack_fileURLToPath__ } from "url"; + import { dirname as __webpack_dirname__ } from "path"; + var src_dirname = __webpack_dirname__(__webpack_fileURLToPath__(import.meta.url)); + var src_filename = __webpack_fileURLToPath__(import.meta.url); + console.log(src_filename); + ``` +- `false`: the `__filename` will be leave as is, which will cause a runtime error when running the output. + +### shims.esm.__dirname + +- **Default:** `false` + +Options: +- `true`: when `format` is `esm`, the `__dirname` in source code will be replaced with the directory name of the current module. + + For example, given the following source code: + + ```js + console.log(__dirname); + ``` + + the ESM output will be transformed to: + + ```js + import { fileURLToPath as __webpack_fileURLToPath__ } from "url"; + import { dirname as __webpack_dirname__ } from "path"; + var src_dirname = __webpack_dirname__(__webpack_fileURLToPath__(import.meta.url)); + console.log(src_dirname); + ``` + +- `false`: the `__dirname` will be leave as is, which will cause a runtime error when running the output. + +### shims.esm.require + +- **Default:** `false` + +Options: +- `true`: when `format` is `esm`, the `require` in source code will be replaced with the directory name of the current module. + + For example, given the following source code: + + ```js + const someModule = require('./someModule'); + + // dynamic require + const dynamicRequiredModule = require(SOME_VALUE_IN_RUNTIME); + // require.resolve + const someModulePath = require.resolve('./someModule'); + // use require as a expression + const lazyFn = (module, requireFn) => {}; + lazyFn('./other.js', require); + ``` + + the ESM output will be transformed to: + + ```js + import __rslib_shim_module__ from 'module'; + const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(import.meta.url); + // dynamic require + require(SOME_VALUE_IN_RUNTIME); + // require.resolve + require.resolve('./someModule'); + // use require as a expression + const lazyFn = (module, requireFn)=>{}; + lazyFn('./other.js', require); + ``` + +- `false`: the `require` will be leave as is, which will cause a runtime error when running the output.