Skip to content

Commit 83ee45c

Browse files
authored
Merge pull request #21411 from akashsonune/fix/remove-export-assignment-to-support-modern-typeScript-esm
fix(types): remove export assignment to support typescript esm compatibility
2 parents 2292edb + 047f05e commit 83ee45c

File tree

22 files changed

+425
-121
lines changed

22 files changed

+425
-121
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ node_modules
171171

172172
test/data/map/tool
173173
test/data/map/raw
174+
175+
/test/types/package-lock.json
176+
174177
theme/thumb
175178
pre-publish-tmp
176179
todo

build/pre-publish.js

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -378,32 +378,43 @@ async function readFilePaths({patterns, cwd}) {
378378
async function bundleDTS() {
379379

380380
const outDir = nodePath.resolve(__dirname, '../types/dist');
381-
const commonConfig = {
382-
onwarn(warning, rollupWarn) {
383-
// Not warn circular dependency
384-
if (warning.code !== 'CIRCULAR_DEPENDENCY') {
385-
rollupWarn(warning);
386-
}
387-
},
388-
plugins: [
389-
dts({
390-
respectExternal: true
391-
})
392-
// {
393-
// generateBundle(options, bundle) {
394-
// for (let chunk of Object.values(bundle)) {
395-
// chunk.code = `
396-
// type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
397-
// ${chunk.code}`
398-
// }
399-
// }
400-
// }
401-
]
402-
};
381+
382+
function createCommonConfig(opt) {
383+
return {
384+
onwarn(warning, rollupWarn) {
385+
// Not warn circular dependency
386+
if (warning.code !== 'CIRCULAR_DEPENDENCY') {
387+
rollupWarn(warning);
388+
}
389+
},
390+
plugins: [
391+
dts({
392+
respectExternal: true,
393+
// - `package.json` `{"type": "module"}` requires explicit file extensions in
394+
// imports; otherwise `tsc` reports error TS(2834).
395+
// - When importing a `.d.ts`, a proper solution can be
396+
// `import {xxx} from "./yyy.js"` instead of `from "./yyy.d.ts"`; otherwise
397+
// `tsc` reports error TS(2846).
398+
// Use `explicitFileExtension: "js"` to use `.js` as the extension of a import paths.
399+
explicitFileExtension: 'js',
400+
umdExportName: opt.umdExportName,
401+
})
402+
// {
403+
// generateBundle(options, bundle) {
404+
// for (let chunk of Object.values(bundle)) {
405+
// chunk.code = `
406+
// type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
407+
// ${chunk.code}`
408+
// }
409+
// }
410+
// }
411+
]
412+
};
413+
}
403414

404415
// Bundle chunks.
405416
const parts = [
406-
'core', 'charts', 'components', 'renderers', 'option', 'features'
417+
'all', 'core', 'charts', 'components', 'renderers', 'option', 'features'
407418
];
408419
const inputs = {};
409420
parts.forEach(partName => {
@@ -412,27 +423,39 @@ async function bundleDTS() {
412423

413424
const bundle = await rollup.rollup({
414425
input: inputs,
415-
...commonConfig
426+
...createCommonConfig({})
416427
});
417-
let idx = 1;
418428
await bundle.write({
419429
dir: outDir,
420430
minifyInternalExports: false,
421431
manualChunks: (id) => {
422-
// Only create one chunk.
432+
// Only create one chunk. All of the public entries should import from 'shared.d.ts';
433+
// otherwise TS error 2442 (Types have separate declarations of a private property)
434+
// may occur.
423435
return 'shared';
424436
},
425437
chunkFileNames: 'shared.d.ts'
426438
});
427439

428-
// Bundle all in one
429-
const bundleAllInOne = await rollup.rollup({
440+
// Bundle a single, self-contained ESM `echarts/types/dist/echarts.d.ts` with no imports,
441+
// for online type checkers (e.g., echarts-examples) usage.
442+
const bundleStandaloneESM = await rollup.rollup({
430443
input: nodePath.resolve(__dirname, `../types/src/export/all.d.ts`),
431-
...commonConfig
444+
...createCommonConfig({})
432445
});
433-
await bundleAllInOne.write({
446+
await bundleStandaloneESM.write({
434447
file: nodePath.resolve(outDir, 'echarts.d.ts')
435448
});
449+
450+
// Bundle a UMD `echarts/types/dist/echarts.d.cts`.
451+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.
452+
const bundleStandaloneCJS = await rollup.rollup({
453+
input: nodePath.resolve(__dirname, `../types/src/export/all.d.ts`),
454+
...createCommonConfig({umdExportName: 'echarts'})
455+
});
456+
await bundleStandaloneCJS.write({
457+
file: nodePath.resolve(outDir, 'echarts.d.cts')
458+
});
436459
}
437460

438461
function readTSConfig() {
@@ -451,8 +474,9 @@ function generateEntries() {
451474
fs.writeFileSync(nodePath.join(__dirname, `../${entryPath}.js`), jsCode, 'utf-8');
452475
}
453476

454-
// Make the d.ts in the same dir as .js, so that the can be found by tsc.
455-
// package.json "types" in "exports" does not always seam to work.
477+
// Create xxx.d.ts in the same dir with xxx.js, so that they can be found by `tsc`.
478+
// This way is more reliable than using "types" field in `package.json` "exports"
479+
// considering older versions of `tsc`.
456480
const dtsCode = fs.readFileSync(nodePath.join(__dirname, `/template/${entryPath}.d.ts`), 'utf-8');
457481
fs.writeFileSync(nodePath.join(__dirname, `../${entryPath}.d.ts`), dtsCode, 'utf-8');
458482
});

build/template/charts.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/charts';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/charts.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/components.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/components';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/components.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/core.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/core';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/core.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/features.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/features';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/features.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/option.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/option';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/option.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/renderers.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/dist/renderers';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
export * from './types/dist/renderers.js';
22+
// See section "TypeScript entries" in `echarts/package.README.md` for more details.

build/template/ssr/client/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export * from './types/index';
20+
// A pseudo `.js` to redirect to `.d.ts`.
21+
// See `package.README.json` for more details.
22+
export * from './types/index.js';

build/testDts.js

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,113 @@ async function installTs() {
3434
}
3535

3636
async function runTests() {
37-
const compilerOptions = {
38-
declaration: false,
39-
importHelpers: false,
40-
sourceMap: false,
41-
pretty: false,
42-
removeComments: false,
43-
allowJs: false,
44-
outDir: __dirname + '/../test/types/tmp',
45-
typeRoots: [__dirname + '/../types/dist'],
46-
rootDir: __dirname + '/../test/types',
47-
48-
// Must pass in most strict cases
49-
strict: true
50-
};
51-
const testsList = await globby(__dirname + '/../test/types/*.ts');
37+
const casesESM = await globby(__dirname + '/../test/types/esm/*.ts');
38+
const casesCJS = await globby(__dirname + '/../test/types/cjs/*.ts');
39+
const casesNoModule = await globby(__dirname + '/../test/types/no-module/*.ts');
5240

5341
const tsVersions = getTypeScriptVersions();
42+
43+
function createCompilerOptions(overrideOptions) {
44+
return {
45+
declaration: false,
46+
importHelpers: false,
47+
sourceMap: false,
48+
pretty: false,
49+
removeComments: false,
50+
allowJs: false,
51+
rootDir: __dirname + '/../test/types',
52+
outDir: __dirname + '/../test/types/tmp',
53+
// Disable global types, necessary to avoid other
54+
// irrelevant node_modules types interference.
55+
typeRoots: [],
56+
// Must pass in most strict cases
57+
strict: true,
58+
...overrideOptions
59+
};
60+
};
61+
62+
async function singleTest(ts, tsVersion, tsconfigModule, tsconfigModuleResolution, testList) {
63+
if (!isSupportedTSConfigModuleField(ts, tsconfigModule)) {
64+
console.log(`Skip: tsVersion: ${tsVersion} does not support {"module": "${tsconfigModule}"}.`);
65+
return;
66+
}
67+
if (!isSupportedTSConfigModuleResolutionField(ts, tsVersion, tsconfigModuleResolution)) {
68+
console.log(`Skip: tsVersion: ${tsVersion} does not support {"moduleResolution": "${tsconfigModuleResolution}"}.`);
69+
return;
70+
}
71+
72+
console.log(`Testing: tsVersion: ${tsVersion}, tsconfig: {"module": "${tsconfigModule}", "moduleResolution": "${tsconfigModuleResolution}"}`);
73+
await runTsCompile(ts, createCompilerOptions({
74+
// noEmit: true,
75+
module: tsconfigModule,
76+
moduleResolution: tsconfigModuleResolution,
77+
}), testList);
78+
}
79+
5480
for (const version of tsVersions) {
55-
console.log(`Testing ts version ${version}`);
5681
const ts = require(typeScriptPath(version));
57-
await runTsCompile(ts, compilerOptions, testsList);
5882

59-
console.log(`Finished test of ts version ${version}`);
83+
// console.log(ts.ModuleKind);
84+
// console.log(ts.ModuleResolutionKind);
85+
86+
// await singleTest(ts, version, undefined , undefined, casesESM);
87+
// await singleTest(ts, version, 'None', 'classic', casesNoModule);
88+
// await singleTest(ts, version, 'CommonJS', 'node', casesESM);
89+
// await singleTest(ts, version, 'CommonJS', 'node', casesCJS);
90+
// await singleTest(ts, version, 'ESNext', 'node', casesESM);
91+
// await singleTest(ts, version, 'ESNext', 'Bundler', casesESM);
92+
await singleTest(ts, version, 'NodeNext', 'NodeNext', casesESM);
93+
// await singleTest(ts, version, 'NodeNext', 'NodeNext', casesCJS);
94+
95+
console.log(`Finished test of tsVersion ${version}`);
96+
}
97+
}
98+
99+
function isSupportedTSConfigModuleField(ts, moduleName) {
100+
if (moduleName === undefined) {
101+
return true;
102+
}
103+
const map = {
104+
'none': 'None',
105+
'commonjs': 'CommonJS',
106+
'amd': 'AMD',
107+
'umd': 'UMD',
108+
'system': 'System',
109+
'es6': 'ES2015',
110+
'es2015': 'ES2015',
111+
'es2020': 'ES2020',
112+
'es2022': 'ES2022',
113+
'esnext': 'ESNext',
114+
'node16': 'Node16',
115+
'nodenext': 'NodeNext',
116+
};
117+
const enumKey = map[moduleName.toLowerCase()];
118+
return enumKey != null && ts.ModuleKind[enumKey] != null;
119+
}
120+
121+
function isSupportedTSConfigModuleResolutionField(ts, tsVersion, moduleResolutionName) {
122+
if (moduleResolutionName === undefined) {
123+
return true;
60124
}
125+
const map = {
126+
'classic': 'Classic',
127+
'node': 'NodeJs',
128+
// 'nodejs': 'NodeJs', // Older TS do not support value "nodejs".
129+
'node10': 'Node10',
130+
'node16': 'Node16',
131+
'nodenext': 'NodeNext',
132+
'bundler': 'Bundler',
133+
};
134+
const enumKey = map[moduleResolutionName.toLowerCase()];
135+
136+
if (enumKey === 'NodeNext') {
137+
// "NodeNext" is unstable before TSv4.7, and error will be thrown.
138+
if (semver.lt(tsVersion + '.0', '4.7.0')) {
139+
return false;
140+
}
141+
}
142+
143+
return enumKey != null && ts.ModuleResolutionKind[enumKey] != null;
61144
}
62145

63146
function getTypeScriptVersions() {

0 commit comments

Comments
 (0)