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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions packages/core/src/loader/file_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export interface FileLoaderParseItem {
type NormalizedFileLoaderOptions = FileLoaderOptions & Required<Pick<FileLoaderOptions, 'caseStyle' | 'loaderFS'>>;

function getDefaultFileLoaderMatch(): string[] {
return isSupportTypeScript() ? ['**/*.(js|ts)', '!**/*.d.ts'] : ['**/*.js'];
return isSupportTypeScript() ? ['**/*.(js|ts|mjs|cjs)', '!**/*.d.ts'] : ['**/*.{js,mjs,cjs}'];
}
Comment on lines 66 to 68

/**
Expand Down Expand Up @@ -220,8 +220,12 @@ export class FileLoader {
for (const filepath of filepaths) {
const fullpath = path.join(directory, filepath);
if (!this.options.loaderFS.stat(fullpath).isFile()) continue;
if (filepath.endsWith('.js')) {
const filepathTs = filepath.replace(/\.js$/, '.ts');
// A compiled `.js` / `.mjs` / `.cjs` sitting next to its `.ts` source (e.g. `tsc`
// or `tsdown` output kept in the same directory during development) must not be
// loaded on top of the source file — otherwise both are attached to the same
// property and `can't overwrite property` is thrown. The `.ts` source always wins.
if (filepath.endsWith('.js') || filepath.endsWith('.mjs') || filepath.endsWith('.cjs')) {
const filepathTs = filepath.replace(/\.(?:js|mjs|cjs)$/, '.ts');
if (filepaths.includes(filepathTs)) {
debug('[parse] ignore %s, because %s exists', fullpath, filepathTs);
continue;
Expand Down
22 changes: 22 additions & 0 deletions packages/core/test/egg-ts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ describe('test/egg-ts.test.ts', () => {
assert(app.serviceClasses.test);
});

it('should load mjs/cjs and prefer the ts source over its compiled mjs/cjs', async () => {
mm(process.env, 'EGG_TYPESCRIPT', 'true');
app = createApp('egg-ts-js');

// loadService must not throw "can't overwrite property" even though
// `dual.ts`+`dual.mjs` and `dualc.ts`+`dualc.cjs` coexist in the directory.
await app.loader.loadService();

// standalone `.mjs` / `.cjs` are scanned and loaded as first-class files
assert(app.serviceClasses.pureMjs);
assert.equal(app.serviceClasses.pureMjs.loadedFrom, 'mjs');
assert(app.serviceClasses.pureCjs);
assert.equal(app.serviceClasses.pureCjs.loadedFrom, 'cjs');

// priority: when a `.ts` source and its compiled `.mjs`/`.cjs` coexist,
// the `.ts` source wins and the compiled sibling is ignored.
assert(app.serviceClasses.dual);
assert.equal(app.serviceClasses.dual.loadedFrom, 'ts');
assert(app.serviceClasses.dualc);
assert.equal(app.serviceClasses.dualc.loadedFrom, 'ts');
});
Comment on lines +130 to +150

it('should auto require tsconfig-paths', async () => {
mm(process.env, 'EGG_TYPESCRIPT', 'true');
app = createApp('egg-ts-js-tsconfig-paths');
Expand Down
7 changes: 7 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/dual.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Compiled output of `dual.ts`. Must be ignored while `dual.ts` exists.
export default class DualServiceMjs {
static loadedFrom = 'mjs';
which() {
return 'mjs';
}
}
8 changes: 8 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/dual.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// `dual.ts` + `dual.mjs` coexist (compiled output kept beside the source).
// The `.ts` source must win; `dual.mjs` must be ignored.
module.exports = class DualService {
static loadedFrom = 'ts';
which() {
return 'ts';
}
};
7 changes: 7 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/dualc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Compiled output of `dualc.ts`. Must be ignored while `dualc.ts` exists.
module.exports = class DualcServiceCjs {
static loadedFrom = 'cjs';
which() {
return 'cjs';
}
};
7 changes: 7 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/dualc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// `dualc.ts` + `dualc.cjs` coexist. The `.ts` source must win; `dualc.cjs` ignored.
module.exports = class DualcService {
static loadedFrom = 'ts';
which() {
return 'ts';
}
};
6 changes: 6 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/pureCjs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = class PureCjsService {
static loadedFrom = 'cjs';
cjs() {
return 'from cjs service';
}
};
6 changes: 6 additions & 0 deletions packages/core/test/fixtures/egg-ts-js/app/service/pureMjs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default class PureMjsService {
static loadedFrom = 'mjs';
mjs() {
return 'from mjs service';
}
}
Loading