From fe7194616f3addbf54b56f5c3475f3ddcc1f72c3 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 31 Oct 2022 10:36:29 +0100 Subject: [PATCH] fix: improve compatibility with native Node CJS resolution (#2226) * fix: improve compatibility with native Node CJS resolution * chore: types * test: increase stacktrace timeout --- packages/vite-node/src/client.ts | 31 +++++++++++++--------------- test/cjs/src/other.cjs | 2 ++ test/cjs/src/other.d.cts | 5 +++++ test/cjs/test/named-default.test.ts | 15 ++++++++++++++ test/stacktraces/test/runner.test.ts | 2 +- 5 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 test/cjs/src/other.cjs create mode 100644 test/cjs/src/other.d.cts create mode 100644 test/cjs/test/named-default.test.ts diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 8563230b0e86..b9456f7da684 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -247,24 +247,21 @@ export class ViteNodeRunner { return Reflect.get(exports, p, receiver) }, set(_, p, value) { - // Node also allows access of named exports via exports.default - // https://nodejs.org/api/esm.html#commonjs-namespaces - if (p !== 'default') { - if (!Reflect.has(exports, 'default')) - exports.default = {} - - // returns undefined, when accessing named exports, if default is not an object - // but is still present inside hasOwnKeys, this is Node behaviour for CJS - if (exports.default === null || typeof exports.default !== 'object') { - defineExport(exports, p, () => undefined) - return true - } - - exports.default[p] = value - defineExport(exports, p, () => value) + if (!Reflect.has(exports, 'default')) + exports.default = {} + + // returns undefined, when accessing named exports, if default is not an object + // but is still present inside hasOwnKeys, this is Node behaviour for CJS + if (exports.default === null || typeof exports.default !== 'object') { + defineExport(exports, p, () => undefined) return true } - return Reflect.set(exports, p, value) + + exports.default[p] = value + if (p !== 'default') + defineExport(exports, p, () => value) + + return true }, }) @@ -274,7 +271,7 @@ export class ViteNodeRunner { const moduleProxy = { set exports(value) { exportAll(cjsExports, value) - cjsExports.default = value + exports.default = value }, get exports() { return cjsExports diff --git a/test/cjs/src/other.cjs b/test/cjs/src/other.cjs new file mode 100644 index 000000000000..35e3bd6e77f9 --- /dev/null +++ b/test/cjs/src/other.cjs @@ -0,0 +1,2 @@ +'use strict' +exports.default = 2 diff --git a/test/cjs/src/other.d.cts b/test/cjs/src/other.d.cts new file mode 100644 index 000000000000..6a16fde0c615 --- /dev/null +++ b/test/cjs/src/other.d.cts @@ -0,0 +1,5 @@ +declare const defaultExports: { + default: number +} + +export default defaultExports diff --git a/test/cjs/test/named-default.test.ts b/test/cjs/test/named-default.test.ts new file mode 100644 index 000000000000..5e7cd5d01d60 --- /dev/null +++ b/test/cjs/test/named-default.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from 'vitest' + +import * as other from '../src/other.cjs' +import defaultOther from '../src/other.cjs' + +describe('correctly identified named default', () => { + it('default should be on default', () => { + expect(other.default).toBe(defaultOther) + }) + + it('default is an object with default', () => { + expect(other.default).toMatchObject({ default: 2 }) + expect(defaultOther).toMatchObject({ default: 2 }) + }) +}) diff --git a/test/stacktraces/test/runner.test.ts b/test/stacktraces/test/runner.test.ts index f5110934e39f..748cf22cae5a 100644 --- a/test/stacktraces/test/runner.test.ts +++ b/test/stacktraces/test/runner.test.ts @@ -31,6 +31,6 @@ describe('stacktraces should respect sourcemaps', async () => { const index = lines.findIndex(val => val.includes(`${file}:`)) const msg = lines.slice(index, index + 8).join('\n') expect(msg).toMatchSnapshot(file) - }, 10000) + }, 30000) } })