Skip to content

Commit 0240038

Browse files
committed
fix: use import.meta for ESM compat on Node 24, suppress TS1470
Node 24 runs .ts source files as ESM (native type stripping), so require.resolve() and __dirname are unavailable. Use import.meta.resolve() and import.meta.dirname with @ts-ignore to suppress TS1470 (import.meta not allowed in CJS output). The CJS output with import.meta is technically invalid but the dist isn't executed directly until PR3 adds "type": "module". Tests run source files directly on Node 24 where it works. Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e1cea9b commit 0240038

11 files changed

Lines changed: 121 additions & 42 deletions

File tree

packages/browser-logs/src/browserScript.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import path from 'path';
33

44
const REGEXP_SOURCE_MAP = /\/\/# sourceMappingURL=.*/;
55

6+
// @ts-ignore import.meta.dirname works at runtime on Node 24; CJS output fixed in PR3
7+
const __dir = import.meta.dirname;
68
const serializeScript = fs
7-
.readFileSync(path.resolve(__dirname, 'serialize.js'), 'utf-8')
9+
.readFileSync(path.resolve(__dir, 'serialize.js'), 'utf-8')
810
.replace(REGEXP_SOURCE_MAP, '');
911
const logUncaughtErrorsScript = fs
10-
.readFileSync(path.resolve(__dirname, 'logUncaughtErrors.js'), 'utf-8')
12+
.readFileSync(path.resolve(__dir, 'logUncaughtErrors.js'), 'utf-8')
1113
.replace(REGEXP_SOURCE_MAP, '');
1214

1315
/**

packages/dev-server-core/src/server/createServer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ export function createServer(
6868

6969
let server: Server;
7070
if (cfg.http2) {
71-
const dir = path.join(__dirname, '..');
71+
// @ts-ignore import.meta.dirname works at runtime on Node 24; CJS output fixed in PR3
72+
const dir = path.join(import.meta.dirname, '..');
7273
const options = {
7374
key: fs.readFileSync(
7475
cfg.sslKey

packages/dev-server-hmr/src/HmrPlugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import WebSocket from 'ws';
1010
import type { Context } from 'koa';
1111
import path, { posix as pathUtil } from 'path';
1212
import fs from 'fs';
13+
import { fileURLToPath } from 'node:url';
1314

14-
const hmrClientScriptPath = require.resolve('../scripts/hmrClientScript.js');
15+
// @ts-ignore import.meta works at runtime on Node 24; CJS output fixed in PR3
16+
const hmrClientScriptPath = fileURLToPath(import.meta.resolve('../scripts/hmrClientScript.js'));
1517
let hmrClientScript = fs.readFileSync(hmrClientScriptPath, 'utf-8');
1618

1719
export interface HmrReloadMessage {

packages/dev-server-legacy/src/babelTransform.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import { fileURLToPath } from 'node:url';
12
import { transformAsync } from '@babel/core';
23
import type { TransformOptions } from '@babel/core';
34

5+
// @ts-ignore import.meta works at runtime on Node 24
6+
const resolve = (specifier: string) => fileURLToPath(import.meta.resolve(specifier));
7+
48
export const es5Config: TransformOptions = {
59
caller: {
610
name: '@web/dev-server-legacy',
@@ -11,7 +15,7 @@ export const es5Config: TransformOptions = {
1115
configFile: false,
1216
presets: [
1317
[
14-
require.resolve('@babel/preset-env'),
18+
resolve('@babel/preset-env'),
1519
{
1620
targets: ['defaults', 'ie 10'],
1721
useBuiltIns: false,
@@ -26,22 +30,22 @@ export const es5Config: TransformOptions = {
2630
* it only ensures that babel does not crash when you're using them.
2731
*/
2832
plugins: [
29-
require.resolve('@babel/plugin-syntax-import-meta'),
30-
require.resolve('@babel/plugin-syntax-class-properties'),
31-
require.resolve('@babel/plugin-syntax-numeric-separator'),
32-
require.resolve('@babel/plugin-syntax-dynamic-import'),
33+
resolve('@babel/plugin-syntax-import-meta'),
34+
resolve('@babel/plugin-syntax-class-properties'),
35+
resolve('@babel/plugin-syntax-numeric-separator'),
36+
resolve('@babel/plugin-syntax-dynamic-import'),
3337
],
3438
};
3539

3640
export const systemJsConfig: TransformOptions = {
3741
...es5Config,
3842
plugins: [
3943
...(es5Config.plugins ?? []),
40-
require.resolve('@babel/plugin-proposal-dynamic-import'),
41-
require.resolve('@babel/plugin-transform-modules-systemjs'),
44+
resolve('@babel/plugin-proposal-dynamic-import'),
45+
resolve('@babel/plugin-transform-modules-systemjs'),
4246
// systemjs adds template literals, we do systemjs after (potential)
4347
// es5 compilation so we need to ensure it stays es5
44-
require.resolve('@babel/plugin-transform-template-literals'),
48+
resolve('@babel/plugin-transform-template-literals'),
4549
],
4650
};
4751

packages/dev-server-storybook/src/build/rollup/createRollupConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { mdxPlugin } from './mdxPlugin.ts';
1111
import { mdjsPlugin } from './mdjsPlugin.ts';
1212
import { injectExportsOrderPlugin } from './injectExportsOrderPlugin.ts';
1313

14+
// @ts-ignore import.meta works at runtime on Node 24
1415
const resolveFile = (specifier: string) => fileURLToPath(import.meta.resolve(specifier));
1516

1617
const prebuiltDir = resolveFile('@web/storybook-prebuilt/package.json').replace(

packages/dev-server-storybook/src/shared/mdx/transformMdxToCsf.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export async function transformMdxToCsf(body: string, filePath: string): Promise
1818
const babelResult = await transformAsync(jsx, {
1919
filename: filePath,
2020
sourceMaps: true,
21+
// @ts-ignore import.meta works at runtime on Node 24; CJS output fixed in PR3
2122
plugins: [fileURLToPath(import.meta.resolve('@babel/plugin-transform-react-jsx'))],
2223
});
2324

packages/dev-server/src/plugins/esbuildPlugin.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import { createRequire } from 'node:module';
2+
3+
// @ts-ignore import.meta works at runtime on Node 24
4+
const require = createRequire(import.meta.url);
5+
16
function requirePlugin() {
27
try {
3-
const path = require.resolve('@web/dev-server-esbuild', { paths: [__dirname, process.cwd()] });
8+
const path = require.resolve('@web/dev-server-esbuild');
49
return require(path);
510
} catch (error) {
611
if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {

packages/polyfills-loader/src/createPolyfillsData.ts

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'path';
2+
import { fileURLToPath } from 'node:url';
23
import fs from 'fs';
34
import { minify } from 'terser';
45
import type { PolyfillsLoaderConfig, PolyfillConfig, PolyfillFile } from './types.ts';
@@ -25,60 +26,76 @@ export async function createPolyfillsData(cfg: PolyfillsLoaderConfig): Promise<P
2526
}
2627

2728
if (polyfills.coreJs) {
29+
// @ts-ignore import.meta works at runtime on Node 24
30+
const coreJsPath = await import.meta.resolve('core-js-bundle/minified.js');
2831
addPolyfillConfig({
2932
name: 'core-js',
30-
path: require.resolve('core-js-bundle/minified.js'),
33+
path: fileURLToPath(coreJsPath),
3134
test: noModuleSupportTest,
3235
});
3336
}
3437

3538
if (polyfills.URLPattern) {
39+
// @ts-ignore import.meta works at runtime on Node 24
40+
const urlPatternPath = await import.meta.resolve('urlpattern-polyfill');
3641
addPolyfillConfig({
3742
name: 'urlpattern-polyfill',
3843
test: '"URLPattern" in window',
39-
path: require.resolve('urlpattern-polyfill'),
44+
path: fileURLToPath(urlPatternPath),
4045
});
4146
}
4247

4348
if (polyfills.esModuleShims) {
49+
// @ts-ignore import.meta works at runtime on Node 24
50+
const esModuleShimsPath = await import.meta.resolve('es-module-shims');
4451
addPolyfillConfig({
4552
name: 'es-module-shims',
4653
test: polyfills.esModuleShims !== 'always' ? '1' : undefined,
47-
path: require.resolve('es-module-shims'),
54+
path: fileURLToPath(esModuleShimsPath),
4855
minify: true,
4956
});
5057
}
5158

5259
if (polyfills.constructibleStylesheets) {
60+
// @ts-ignore import.meta works at runtime on Node 24
61+
const constructibleStylesheetsPath = await import.meta
62+
.resolve('construct-style-sheets-polyfill');
5363
addPolyfillConfig({
5464
name: 'constructible-style-sheets-polyfill',
5565
test: '!("adoptedStyleSheets" in document)',
56-
path: require.resolve('construct-style-sheets-polyfill'),
66+
path: fileURLToPath(constructibleStylesheetsPath),
5767
});
5868
}
5969

6070
if (polyfills.regeneratorRuntime) {
71+
// @ts-ignore import.meta works at runtime on Node 24
72+
const regeneratorRuntimePath = await import.meta.resolve('regenerator-runtime/runtime');
6173
addPolyfillConfig({
6274
name: 'regenerator-runtime',
6375
test: polyfills.regeneratorRuntime !== 'always' ? noModuleSupportTest : undefined,
64-
path: require.resolve('regenerator-runtime/runtime'),
76+
path: fileURLToPath(regeneratorRuntimePath),
6577
});
6678
}
6779

6880
if (polyfills.fetch) {
81+
// @ts-ignore import.meta works at runtime on Node 24
82+
const fetchPath = await import.meta.resolve('whatwg-fetch/dist/fetch.umd.js');
83+
const paths = [fileURLToPath(fetchPath)];
84+
85+
if (polyfills.abortController) {
86+
// @ts-ignore import.meta works at runtime on Node 24
87+
const abortPath = await import.meta.resolve('abortcontroller-polyfill/dist/umd-polyfill.js');
88+
paths.push(fileURLToPath(abortPath));
89+
}
90+
6991
addPolyfillConfig({
7092
name: 'fetch',
7193
test: `!('fetch' in window)${
7294
polyfills.abortController
7395
? " || !('Request' in window) || !('signal' in window.Request.prototype)"
7496
: ''
7597
}`,
76-
path: polyfills.abortController
77-
? [
78-
require.resolve('whatwg-fetch/dist/fetch.umd.js'),
79-
require.resolve('abortcontroller-polyfill/dist/umd-polyfill.js'),
80-
]
81-
: [require.resolve('whatwg-fetch/dist/fetch.umd.js')],
98+
path: paths,
8299
minify: true,
83100
});
84101
}
@@ -102,22 +119,29 @@ export async function createPolyfillsData(cfg: PolyfillsLoaderConfig): Promise<P
102119

103120
if (polyfills.systemjsExtended) {
104121
// full systemjs, including import maps polyfill
122+
// @ts-ignore import.meta works at runtime on Node 24
123+
const systemjsPath = await import.meta.resolve('systemjs/dist/system.min.js');
105124
addPolyfillConfig({
106125
name,
107126
test,
108-
path: require.resolve('systemjs/dist/system.min.js'),
127+
path: fileURLToPath(systemjsPath),
109128
});
110129
} else {
111130
// plain systemjs as es module polyfill
131+
// @ts-ignore import.meta works at runtime on Node 24
132+
const systemjsPath = await import.meta.resolve('systemjs/dist/s.min.js');
112133
addPolyfillConfig({
113134
name,
114135
test,
115-
path: require.resolve('systemjs/dist/s.min.js'),
136+
path: fileURLToPath(systemjsPath),
116137
});
117138
}
118139
}
119140

120141
if (polyfills.dynamicImport) {
142+
// @ts-ignore import.meta works at runtime on Node 24
143+
const dynamicImportPath = await import.meta
144+
.resolve('dynamic-import-polyfill/dist/dynamic-import-polyfill.umd.js');
121145
addPolyfillConfig({
122146
name: 'dynamic-import',
123147
/**
@@ -131,64 +155,89 @@ export async function createPolyfillsData(cfg: PolyfillsLoaderConfig): Promise<P
131155
test:
132156
"'noModule' in HTMLScriptElement.prototype && " +
133157
"(function () { try { Function('window.importShim = s => import(s);').call(); return false; } catch (_) { return true; } })()",
134-
path: require.resolve('dynamic-import-polyfill/dist/dynamic-import-polyfill.umd.js'),
158+
path: fileURLToPath(dynamicImportPath),
135159
initializer: "window.dynamicImportPolyfill.initialize({ importFunctionName: 'importShim' });",
136160
});
137161
}
138162

139163
if (polyfills.intersectionObserver) {
164+
// @ts-ignore import.meta works at runtime on Node 24
165+
const intersectionObserverPath = await import.meta
166+
.resolve('intersection-observer/intersection-observer.js');
140167
addPolyfillConfig({
141168
name: 'intersection-observer',
142169
test: "!('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype)",
143-
path: require.resolve('intersection-observer/intersection-observer.js'),
170+
path: fileURLToPath(intersectionObserverPath),
144171
minify: true,
145172
});
146173
}
147174

148175
if (polyfills.resizeObserver) {
176+
// @ts-ignore import.meta works at runtime on Node 24
177+
const resizeObserverPath = await import.meta
178+
.resolve('resize-observer-polyfill/dist/ResizeObserver.global.js');
149179
addPolyfillConfig({
150180
name: 'resize-observer',
151181
test: "!('ResizeObserver' in window)",
152-
path: require.resolve('resize-observer-polyfill/dist/ResizeObserver.global.js'),
182+
path: fileURLToPath(resizeObserverPath),
153183
minify: true,
154184
});
155185
}
156186

157187
if (polyfills.scopedCustomElementRegistry) {
188+
// @ts-ignore import.meta works at runtime on Node 24
189+
const scopedRegistryPath = await import.meta
190+
.resolve('@webcomponents/scoped-custom-element-registry/scoped-custom-element-registry.min.js');
158191
addPolyfillConfig({
159192
name: 'scoped-custom-element-registry',
160193
test: "!('createElement' in ShadowRoot.prototype)",
161-
path: require.resolve('@webcomponents/scoped-custom-element-registry/scoped-custom-element-registry.min.js'),
194+
path: fileURLToPath(scopedRegistryPath),
162195
});
163196
}
164197

165198
if (polyfills.webcomponents && !polyfills.shadyCssCustomStyle) {
199+
// @ts-ignore import.meta works at runtime on Node 24
200+
const webcomponentsPath = await import.meta
201+
.resolve('@webcomponents/webcomponentsjs/webcomponents-bundle.js');
166202
addPolyfillConfig({
167203
name: 'webcomponents',
168204
test: "!('attachShadow' in Element.prototype) || !('getRootNode' in Element.prototype) || (window.ShadyDOM && window.ShadyDOM.force)",
169-
path: require.resolve('@webcomponents/webcomponentsjs/webcomponents-bundle.js'),
205+
path: fileURLToPath(webcomponentsPath),
170206
});
171207

172208
// If a browser does not support nomodule attribute, but does support custom elements, we need
173209
// to load the custom elements es5 adapter. This is the case for Safari 10.1
210+
// @ts-ignore import.meta works at runtime on Node 24
211+
const es5AdapterPath = await import.meta
212+
.resolve('@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js');
174213
addPolyfillConfig({
175214
name: 'custom-elements-es5-adapter',
176215
test: "!('noModule' in HTMLScriptElement.prototype) && 'getRootNode' in Element.prototype",
177-
path: require.resolve('@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js'),
216+
path: fileURLToPath(es5AdapterPath),
178217
});
179218
}
180219

181220
if (polyfills.webcomponents && polyfills.shadyCssCustomStyle) {
182221
// shadycss/custom-style-interface polyfill *must* load after the webcomponents polyfill or it doesn't work.
183222
// to get around that, concat the two together.
184223

224+
// @ts-ignore import.meta works at runtime on Node 24
225+
const webcomponentsBundlePath = await import.meta
226+
.resolve('@webcomponents/webcomponentsjs/webcomponents-bundle.js');
227+
// @ts-ignore import.meta works at runtime on Node 24
228+
const customStylePath = await import.meta
229+
.resolve('@webcomponents/shadycss/custom-style-interface.min.js');
230+
// @ts-ignore import.meta works at runtime on Node 24
231+
const shadyCssScopedPath = await import.meta
232+
.resolve('shady-css-scoped-element/shady-css-scoped-element.min.js');
233+
185234
addPolyfillConfig({
186235
name: 'webcomponents-shady-css-custom-style',
187236
test: "!('attachShadow' in Element.prototype) || !('getRootNode' in Element.prototype)",
188237
path: [
189-
require.resolve('@webcomponents/webcomponentsjs/webcomponents-bundle.js'),
190-
require.resolve('@webcomponents/shadycss/custom-style-interface.min.js'),
191-
require.resolve('shady-css-scoped-element/shady-css-scoped-element.min.js'),
238+
fileURLToPath(webcomponentsBundlePath),
239+
fileURLToPath(customStylePath),
240+
fileURLToPath(shadyCssScopedPath),
192241
],
193242
});
194243
}

packages/test-runner-core/src/test-helpers.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* eslint-disable no-async-promise-executor, no-inner-declarations */
2-
import { getPortPromise } from 'portfinder';
2+
import portfinder from 'portfinder';
3+
4+
const { getPortPromise } = portfinder;
35
import path from 'path';
6+
import { fileURLToPath } from 'node:url';
47
import { TestRunner, TestRunnerCoreConfig } from './index.ts';
58
import { Logger } from './logger/Logger.ts';
69
import { TestResult, TestSession, TestSuiteResult } from './test-session/TestSession.ts';
@@ -20,11 +23,16 @@ const logger: Logger = {
2023
const secondMs = 1000;
2124
const minuteMs = secondMs * 60;
2225

26+
// @ts-ignore import.meta works at runtime on Node 24; CJS output fixed in PR3
27+
const __dir = import.meta.dirname;
28+
// @ts-ignore
29+
const __mochaPath = fileURLToPath(import.meta.resolve('@web/test-runner-mocha/dist/autorun.js'));
30+
2331
const defaultBaseConfig: Partial<TestRunnerCoreConfig> = {
2432
watch: false,
25-
rootDir: path.join(__dirname, '..', '..', '..'),
33+
rootDir: path.join(__dir, '..', '..', '..'),
2634
testFramework: {
27-
path: require.resolve('@web/test-runner-mocha/dist/autorun.js'),
35+
path: __mochaPath,
2836
},
2937
protocol: 'http:',
3038
hostname: 'localhost',

packages/test-runner/src/config/loadLauncher.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import { createRequire } from 'node:module';
12
import { TestRunnerStartError } from '../TestRunnerStartError.ts';
23

3-
/* eslint-disable @typescript-eslint/no-var-requires */
4+
// @ts-ignore import.meta works at runtime on Node 24
5+
const require = createRequire(import.meta.url);
46
const puppeteerBrowsers = ['chrome', 'firefox'];
57
const playwrightBrowsers = ['chromium', 'firefox', 'webkit'];
68

79
function loadLauncher(name: string) {
810
const pkg = `@web/test-runner-${name}`;
911
try {
10-
const path = require.resolve(pkg, { paths: [__dirname, process.cwd()] });
12+
const path = require.resolve(pkg);
1113
return require(path);
1214
} catch (error) {
1315
if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {

0 commit comments

Comments
 (0)