1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | const nodePath = require('path');
|
32 | const assert = require('assert');
|
33 | const fs = require('fs');
|
34 | const fsExtra = require('fs-extra');
|
35 | const chalk = require('chalk');
|
36 | const ts = require('typescript');
|
37 | const globby = require('globby');
|
38 | const transformDEVUtil = require('./transform-dev');
|
39 | const preamble = require('./preamble');
|
40 | const dts = require('@lang/rollup-plugin-dts').default;
|
41 | const rollup = require('rollup');
|
42 |
|
43 | const ecDir = nodePath.resolve(__dirname, '..');
|
44 | const tmpDir = nodePath.resolve(ecDir, 'pre-publish-tmp');
|
45 |
|
46 | const tsConfig = readTSConfig();
|
47 |
|
48 | const autoGeneratedFileAlert = `
|
49 | /**
|
50 | * AUTO-GENERATED FILE. DO NOT MODIFY.
|
51 | */
|
52 |
|
53 | `;
|
54 |
|
55 | const mainSrcGlobby = {
|
56 | patterns: [
|
57 | 'src/**/*.ts'
|
58 | ],
|
59 | cwd: ecDir
|
60 | };
|
61 | const extensionSrcGlobby = {
|
62 | patterns: [
|
63 | 'extension-src/**/*.ts'
|
64 | ],
|
65 | cwd: ecDir
|
66 | };
|
67 | const extensionSrcDir = nodePath.resolve(ecDir, 'extension-src');
|
68 | const extensionESMDir = nodePath.resolve(ecDir, 'extension');
|
69 |
|
70 | const typesDir = nodePath.resolve(ecDir, 'types');
|
71 | const esmDir = 'lib';
|
72 |
|
73 |
|
74 | const compileWorkList = [
|
75 | {
|
76 | logLabel: 'main ts -> js-esm',
|
77 | compilerOptionsOverride: {
|
78 | module: 'ES2015',
|
79 | rootDir: ecDir,
|
80 | outDir: tmpDir,
|
81 |
|
82 | declaration: true,
|
83 | declarationDir: typesDir
|
84 | },
|
85 | srcGlobby: mainSrcGlobby,
|
86 | transformOptions: {
|
87 | filesGlobby: {patterns: ['**/*.js'], cwd: tmpDir},
|
88 | preamble: preamble.js,
|
89 | transformDEV: true
|
90 | },
|
91 | before: async function () {
|
92 | fsExtra.removeSync(tmpDir);
|
93 | fsExtra.removeSync(nodePath.resolve(ecDir, 'types'));
|
94 | fsExtra.removeSync(nodePath.resolve(ecDir, esmDir));
|
95 | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.js'));
|
96 | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.blank.js'));
|
97 | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.common.js'));
|
98 | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.simple.js'));
|
99 | },
|
100 | after: async function () {
|
101 | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.all.js'), nodePath.resolve(ecDir, 'index.js'));
|
102 | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.blank.js'), nodePath.resolve(ecDir, 'index.blank.js'));
|
103 | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.common.js'), nodePath.resolve(ecDir, 'index.common.js'));
|
104 | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.simple.js'), nodePath.resolve(ecDir, 'index.simple.js'));
|
105 | fs.renameSync(nodePath.resolve(tmpDir, 'src'), nodePath.resolve(ecDir, esmDir));
|
106 |
|
107 | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.js'), esmDir);
|
108 | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.blank.js'), esmDir);
|
109 | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.common.js'), esmDir);
|
110 | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.simple.js'), esmDir);
|
111 |
|
112 | await transformDistributionFiles(nodePath.resolve(ecDir, esmDir), esmDir);
|
113 | await transformDistributionFiles(nodePath.resolve(ecDir, 'types'), esmDir);
|
114 | fsExtra.removeSync(tmpDir);
|
115 | }
|
116 | },
|
117 | {
|
118 | logLabel: 'extension ts -> js-esm',
|
119 | compilerOptionsOverride: {
|
120 | module: 'ES2015',
|
121 | rootDir: extensionSrcDir,
|
122 | outDir: extensionESMDir
|
123 | },
|
124 | srcGlobby: extensionSrcGlobby,
|
125 | transformOptions: {
|
126 | filesGlobby: {patterns: ['**/*.js'], cwd: extensionESMDir},
|
127 | preamble: preamble.js,
|
128 | transformDEV: true
|
129 | },
|
130 | before: async function () {
|
131 | fsExtra.removeSync(extensionESMDir);
|
132 | },
|
133 | after: async function () {
|
134 | await transformDistributionFiles(extensionESMDir, 'lib');
|
135 | }
|
136 | }
|
137 | ];
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | module.exports = async function () {
|
145 |
|
146 | for (let {
|
147 | logLabel, compilerOptionsOverride, srcGlobby,
|
148 | transformOptions, before, after
|
149 | } of compileWorkList) {
|
150 |
|
151 | process.stdout.write(chalk.green.dim(`[${logLabel}]: compiling ...`));
|
152 |
|
153 | before && await before();
|
154 |
|
155 | let srcPathList = await readFilePaths(srcGlobby);
|
156 |
|
157 | await tsCompile(compilerOptionsOverride, srcPathList);
|
158 |
|
159 | process.stdout.write(chalk.green.dim(` done \n`));
|
160 |
|
161 | process.stdout.write(chalk.green.dim(`[${logLabel}]: transforming ...`));
|
162 |
|
163 | await transformCode(transformOptions);
|
164 |
|
165 | after && await after();
|
166 |
|
167 | process.stdout.write(chalk.green.dim(` done \n`));
|
168 | }
|
169 |
|
170 | process.stdout.write(chalk.green.dim(`Generating entries ...`));
|
171 | generateEntries();
|
172 | process.stdout.write(chalk.green.dim(`Bundling DTS ...`));
|
173 | await bundleDTS();
|
174 |
|
175 | console.log(chalk.green.dim('All done.'));
|
176 | };
|
177 |
|
178 | async function runTsCompile(localTs, compilerOptions, srcPathList) {
|
179 |
|
180 |
|
181 | const {options, errors} = localTs.convertCompilerOptionsFromJson(compilerOptions, ecDir);
|
182 |
|
183 | if (errors.length) {
|
184 | let errMsg = 'tsconfig parse failed: '
|
185 | + errors.map(error => error.messageText).join('. ')
|
186 | + '\n compilerOptions: \n' + JSON.stringify(compilerOptions, null, 4);
|
187 | assert(false, errMsg);
|
188 | }
|
189 |
|
190 |
|
191 |
|
192 | let program = localTs.createProgram(srcPathList, options);
|
193 | let emitResult = program.emit();
|
194 |
|
195 | let allDiagnostics = localTs
|
196 | .getPreEmitDiagnostics(program)
|
197 | .concat(emitResult.diagnostics);
|
198 |
|
199 | allDiagnostics.forEach(diagnostic => {
|
200 | if (diagnostic.file) {
|
201 | let {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
202 | let message = localTs.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
203 | console.log(chalk.red(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`));
|
204 | }
|
205 | else {
|
206 | console.log(chalk.red(localTs.flattenDiagnosticMessageText(diagnostic.messageText, '\n')));
|
207 | }
|
208 | });
|
209 | if (allDiagnostics.length > 0) {
|
210 | throw new Error('TypeScript Compile Failed')
|
211 | }
|
212 | }
|
213 | module.exports.runTsCompile = runTsCompile;
|
214 |
|
215 | async function tsCompile(compilerOptionsOverride, srcPathList) {
|
216 | assert(
|
217 | compilerOptionsOverride
|
218 | && compilerOptionsOverride.module
|
219 | && compilerOptionsOverride.rootDir
|
220 | && compilerOptionsOverride.outDir
|
221 | );
|
222 |
|
223 | let compilerOptions = {
|
224 | ...tsConfig.compilerOptions,
|
225 | ...compilerOptionsOverride,
|
226 | sourceMap: false
|
227 | };
|
228 |
|
229 | runTsCompile(ts, compilerOptions, srcPathList);
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | function transformRootFolderInEntry(entryFile, replacement) {
|
236 | let code = fs.readFileSync(entryFile, 'utf-8');
|
237 |
|
238 |
|
239 | assert(
|
240 | !/(import\s+|from\s+|require\(\s*)["']\.\/echarts\./.test(code)
|
241 | && !/(import\s+|from\s+|require\(\s*)["']echarts\./.test(code),
|
242 | 'Import echarts.xxx.ts is not supported.'
|
243 | );
|
244 | code = code.replace(/((import\s+|from\s+|require\(\s*)["'])\.\//g, `$1./${replacement}/`);
|
245 | fs.writeFileSync(
|
246 | entryFile,
|
247 |
|
248 | singleTransformZRRootFolder(code, replacement),
|
249 | 'utf-8'
|
250 | );
|
251 | }
|
252 |
|
253 |
|
254 |
|
255 |
|
256 | async function transformDistributionFiles(rooltFolder, replacement) {
|
257 | const files = await readFilePaths({
|
258 | patterns: ['**/*.js', '**/*.d.ts'],
|
259 | cwd: rooltFolder
|
260 | });
|
261 |
|
262 |
|
263 | for (let fileName of files) {
|
264 | let code = fs.readFileSync(fileName, 'utf-8');
|
265 | code = singleTransformZRRootFolder(code, replacement);
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 | fs.writeFileSync(fileName, code, 'utf-8');
|
272 | }
|
273 | }
|
274 |
|
275 | function singleTransformZRRootFolder(code, replacement) {
|
276 | return code.replace(/([\"\'])zrender\/src\//g, `$1zrender/${replacement}/`);
|
277 | }
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 | async function transformCode({filesGlobby, preamble, transformDEV}) {
|
290 |
|
291 | let filePaths = await readFilePaths(filesGlobby);
|
292 |
|
293 | filePaths.map(filePath => {
|
294 | let code = fs.readFileSync(filePath, 'utf8');
|
295 |
|
296 | if (transformDEV) {
|
297 | let result = transformDEVUtil.transform(code, false);
|
298 | code = result.code;
|
299 | }
|
300 |
|
301 | code = autoGeneratedFileAlert + code;
|
302 |
|
303 | if (preamble) {
|
304 | code = preamble + code;
|
305 | }
|
306 |
|
307 | fs.writeFileSync(filePath, code, 'utf8');
|
308 | });
|
309 | }
|
310 |
|
311 | async function readFilePaths({patterns, cwd}) {
|
312 | assert(patterns && cwd);
|
313 | return (
|
314 | await globby(patterns, {cwd})
|
315 | ).map(
|
316 | srcPath => nodePath.resolve(cwd, srcPath)
|
317 | );
|
318 | }
|
319 |
|
320 | async function bundleDTS() {
|
321 |
|
322 | const outDir = nodePath.resolve(__dirname, '../types/dist');
|
323 | const commonConfig = {
|
324 | onwarn(warning, rollupWarn) {
|
325 |
|
326 | if (warning.code !== 'CIRCULAR_DEPENDENCY') {
|
327 | rollupWarn(warning);
|
328 | }
|
329 | },
|
330 | plugins: [
|
331 | dts({
|
332 | respectExternal: true
|
333 | })
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | ]
|
344 | };
|
345 |
|
346 |
|
347 | const parts = [
|
348 | 'core', 'charts', 'components', 'renderers', 'option', 'features'
|
349 | ];
|
350 | const inputs = {};
|
351 | parts.forEach(partName => {
|
352 | inputs[partName] = nodePath.resolve(__dirname, `../types/src/export/${partName}.d.ts`)
|
353 | });
|
354 |
|
355 | const bundle = await rollup.rollup({
|
356 | input: inputs,
|
357 | ...commonConfig
|
358 | });
|
359 | let idx = 1;
|
360 | await bundle.write({
|
361 | dir: outDir,
|
362 | minifyInternalExports: false,
|
363 | manualChunks: (id) => {
|
364 |
|
365 | return 'shared';
|
366 | },
|
367 | chunkFileNames: 'shared.d.ts'
|
368 | });
|
369 |
|
370 |
|
371 | const bundleAllInOne = await rollup.rollup({
|
372 | input: nodePath.resolve(__dirname, `../types/src/export/all.d.ts`),
|
373 | ...commonConfig
|
374 | });
|
375 | await bundleAllInOne.write({
|
376 | file: nodePath.resolve(outDir, 'echarts.d.ts')
|
377 | });
|
378 | }
|
379 |
|
380 | function readTSConfig() {
|
381 |
|
382 |
|
383 | let filePath = nodePath.resolve(ecDir, 'tsconfig.json');
|
384 | const tsConfigText = fs.readFileSync(filePath, {encoding: 'utf8'});
|
385 | return (new Function(`return ( ${tsConfigText} )`))();
|
386 | }
|
387 |
|
388 |
|
389 | function generateEntries() {
|
390 | ['charts', 'components', 'renderers', 'core', 'features'].forEach(entryName => {
|
391 | if (entryName !== 'option') {
|
392 | const jsCode = fs.readFileSync(nodePath.join(__dirname, `template/${entryName}.js`), 'utf-8');
|
393 | fs.writeFileSync(nodePath.join(__dirname, `../${entryName}.js`), jsCode, 'utf-8');
|
394 | }
|
395 |
|
396 | const dtsCode = fs.readFileSync(nodePath.join(__dirname, `/template/${entryName}.d.ts`), 'utf-8');
|
397 | fs.writeFileSync(nodePath.join(__dirname, `../${entryName}.d.ts`), dtsCode, 'utf-8');
|
398 | });
|
399 | }
|
400 |
|
401 | module.exports.readTSConfig = readTSConfig;
|