@bleedingdev/modern-js-server-utils 3.2.0-ultramodern.99 → 3.4.0-ultramodern.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,11 @@ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/
3
3
  import { fs, getAliasConfig, logger } from "@modern-js/utils";
4
4
  import { spawn } from "child_process";
5
5
  import path from "path";
6
+ import { rewriteImportSpecifiers } from "./importRewriter.mjs";
6
7
  import { createTsconfigPathsMatcher, getNotAliasedPath } from "./tsconfigPathsPlugin.mjs";
7
- const importSpecifierRE = /((?:from\s*|import\s*\(\s*|require\s*\(\s*)['"])([^'"]+)(['"])/g;
8
+ import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
9
+ import { dirname as __rspack_dirname } from "node:path";
10
+ var typescript_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
8
11
  const copyFiles = async (from, to, appDirectory)=>{
9
12
  if (await fs.pathExists(from)) {
10
13
  const relativePath = path.relative(appDirectory, from);
@@ -17,42 +20,58 @@ const copyFiles = async (from, to, appDirectory)=>{
17
20
  });
18
21
  }
19
22
  };
20
- const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs)=>{
21
- const output = await runTsgo([
23
+ let resolvedConfigCount = 0;
24
+ const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs, moduleType, tsgoBinPath)=>{
25
+ const tsconfigDir = path.dirname(tsconfigPath);
26
+ const output = await runTsgo(tsgoBinPath, [
22
27
  '--showConfig',
23
28
  '-p',
24
29
  tsconfigPath
25
30
  ], {
26
- cwd: path.dirname(tsconfigPath)
31
+ cwd: tsconfigDir
27
32
  });
28
33
  const config = JSON.parse(output.stdout);
29
34
  config.compilerOptions ??= {};
30
35
  config.compilerOptions.rootDir = appDirectory;
31
36
  config.compilerOptions.outDir = distDir;
32
- config.files = filterSourceFiles(appDirectory, sourceDirs, config.files);
37
+ config.files = filterSourceFiles(tsconfigDir, sourceDirs, config.files);
33
38
  delete config.include;
34
39
  delete config.compilerOptions.baseUrl;
35
40
  if ([
36
41
  'node',
37
42
  'node10'
38
43
  ].includes(String(config.compilerOptions.moduleResolution).toLowerCase())) delete config.compilerOptions.moduleResolution;
39
- const resolvedConfigPath = path.join(appDirectory, `.tsgo.${process.pid}.resolved.json`);
44
+ if ('module' !== moduleType) {
45
+ if ([
46
+ 'preserve',
47
+ 'esnext',
48
+ 'es2015',
49
+ 'es2020',
50
+ 'es2022',
51
+ 'es6'
52
+ ].includes(String(config.compilerOptions.module).toLowerCase())) {
53
+ config.compilerOptions.module = 'commonjs';
54
+ delete config.compilerOptions.moduleResolution;
55
+ }
56
+ config.compilerOptions.verbatimModuleSyntax = false;
57
+ }
58
+ const resolvedConfigPath = path.join(tsconfigDir, `.tsgo.${process.pid}.${resolvedConfigCount++}.resolved.json`);
40
59
  await fs.writeFile(resolvedConfigPath, JSON.stringify(config, null, 2));
41
60
  return {
42
61
  config,
43
62
  resolvedConfigPath
44
63
  };
45
64
  };
46
- const filterSourceFiles = (appDirectory, sourceDirs, files = [])=>{
65
+ const filterSourceFiles = (tsconfigDir, sourceDirs, files = [])=>{
47
66
  const sourcePosixPaths = sourceDirs.map((sourceDir)=>sourceDir.split(path.sep).join(path.posix.sep));
48
67
  return files.filter((fileName)=>{
49
- const absoluteFileName = path.resolve(appDirectory, fileName).split(path.sep).join(path.posix.sep);
68
+ const absoluteFileName = path.resolve(tsconfigDir, fileName).split(path.sep).join(path.posix.sep);
50
69
  return fileName.endsWith('.d.ts') || sourcePosixPaths.some((sourceDir)=>absoluteFileName.includes(sourceDir));
51
70
  });
52
71
  };
53
- const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
72
+ const runTsgo = (tsgoBinPath, args, options)=>new Promise((resolve, reject)=>{
54
73
  const child = spawn(process.execPath, [
55
- getTsgoBinPath(),
74
+ tsgoBinPath,
56
75
  ...args
57
76
  ], {
58
77
  cwd: options.cwd,
@@ -81,14 +100,51 @@ const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
81
100
  resolve(result);
82
101
  });
83
102
  });
84
- const getTsgoBinPath = ()=>path.join(path.dirname(require.resolve("@typescript/native-preview/package.json")), 'bin/tsgo.js');
103
+ const getTsgoBinPath = (appDirectory, resolvePaths = [
104
+ appDirectory,
105
+ typescript_dirname
106
+ ])=>{
107
+ try {
108
+ const pkgPath = require.resolve("@typescript/native-preview/package.json", {
109
+ paths: resolvePaths
110
+ });
111
+ return path.join(path.dirname(pkgPath), 'bin/tsgo.js');
112
+ } catch {
113
+ throw new Error('tsgo could not be found! Please install "@typescript/native-preview" in your project to compile BFF/server code.');
114
+ }
115
+ };
116
+ const OUTPUT_SOURCE_EXTENSIONS = {
117
+ '.js': [
118
+ '.ts',
119
+ '.tsx',
120
+ '.js',
121
+ '.jsx'
122
+ ],
123
+ '.mjs': [
124
+ '.mts',
125
+ '.mjs'
126
+ ],
127
+ '.cjs': [
128
+ '.cts',
129
+ '.cjs'
130
+ ]
131
+ };
85
132
  const getSourceFileForOutput = (appDirectory, distDir, outputFile)=>{
86
133
  const relativeOutput = path.relative(distDir, outputFile);
87
134
  const parsed = path.parse(relativeOutput);
88
135
  const sourceBase = path.join(appDirectory, parsed.dir, parsed.name);
89
- return findExistingSource(`${sourceBase}.ts`) || findExistingSource(`${sourceBase}.tsx`) || findExistingSource(`${sourceBase}.js`) || findExistingSource(`${sourceBase}.jsx`);
136
+ const extensions = OUTPUT_SOURCE_EXTENSIONS[parsed.ext] ?? OUTPUT_SOURCE_EXTENSIONS['.js'];
137
+ for (const extension of extensions){
138
+ const candidate = `${sourceBase}${extension}`;
139
+ if (fs.existsSync(candidate)) return candidate;
140
+ }
141
+ };
142
+ const sourceMappingUrlRE = /^\/\/[#@] sourceMappingURL=.*$/gm;
143
+ const dropStaleSourceMap = async (outputFile, content)=>{
144
+ const mapFile = `${outputFile}.map`;
145
+ if (await fs.pathExists(mapFile)) await fs.remove(mapFile);
146
+ return content.replace(sourceMappingUrlRE, '');
90
147
  };
91
- const findExistingSource = (filePath)=>fs.existsSync(filePath) ? filePath : void 0;
92
148
  const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, moduleType)=>{
93
149
  if (0 === Object.keys(paths).length || !await fs.pathExists(distDir)) return;
94
150
  const matcher = createTsconfigPathsMatcher(baseUrl, paths);
@@ -98,14 +154,8 @@ const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, mo
98
154
  const sourceFile = getSourceFileForOutput(appDirectory, distDir, file);
99
155
  if (!sourceFile) return;
100
156
  const content = await fs.readFile(file, 'utf8');
101
- let changed = false;
102
- const rewritten = content.replace(importSpecifierRE, (match, prefix, specifier, suffix)=>{
103
- const nextSpecifier = getNotAliasedPath(sourceFile, matcher, specifier, moduleType);
104
- if (!nextSpecifier || nextSpecifier === specifier) return match;
105
- changed = true;
106
- return `${prefix}${nextSpecifier}${suffix}`;
107
- });
108
- if (changed) await fs.writeFile(file, rewritten);
157
+ const { content: rewritten, changed } = rewriteImportSpecifiers(content, (specifier)=>getNotAliasedPath(sourceFile, matcher, specifier, moduleType));
158
+ if (changed) await fs.writeFile(file, await dropStaleSourceMap(file, rewritten));
109
159
  }));
110
160
  };
111
161
  const collectOutputFiles = async (dir)=>{
@@ -131,24 +181,34 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
131
181
  tsconfigPath
132
182
  });
133
183
  const { paths = {}, absoluteBaseUrl = './' } = aliasOption;
134
- const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs);
135
- const result = await runTsgo([
136
- '-p',
137
- resolvedConfigPath
138
- ], {
139
- cwd: appDirectory,
140
- reject: false
141
- });
142
- await fs.remove(resolvedConfigPath);
184
+ const tsgoBinPath = getTsgoBinPath(appDirectory);
185
+ const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs, compileOptions.moduleType, tsgoBinPath);
186
+ let result;
187
+ try {
188
+ result = await runTsgo(tsgoBinPath, [
189
+ '-p',
190
+ resolvedConfigPath
191
+ ], {
192
+ cwd: appDirectory,
193
+ reject: false
194
+ });
195
+ } finally{
196
+ await fs.remove(resolvedConfigPath);
197
+ }
143
198
  if (result.stderr) logger.error(result.stderr);
144
199
  if (result.stdout) logger.info(result.stdout);
145
200
  if (0 !== result.code) {
146
201
  const noEmitOnError = tsgoConfig.compilerOptions?.noEmitOnError;
147
- if (void 0 === noEmitOnError || true === noEmitOnError) if (compileOptions.throwErrorInsteadOfExit) logger.error('TS-Go compilation failed');
148
- else process.exit(1);
202
+ if (void 0 === noEmitOnError || true === noEmitOnError) if (compileOptions.throwErrorInsteadOfExit) {
203
+ logger.error('TS-Go compilation failed');
204
+ throw new Error([
205
+ `TS-Go compilation failed with exit code ${result.code}.`,
206
+ result.stderr.trim() || result.stdout.trim()
207
+ ].filter(Boolean).join('\n'));
208
+ } else process.exit(1);
149
209
  }
150
210
  await rewriteOutputSpecifiers(appDirectory, distDir, absoluteBaseUrl, paths, compileOptions.moduleType);
151
211
  for (const source of sourceDirs)await copyFiles(source, distDir, appDirectory);
152
212
  logger.info("TS-Go compile succeed");
153
213
  };
154
- export { compileByTs };
214
+ export { compileByTs, createResolvedTsgoConfig, getTsgoBinPath, rewriteOutputSpecifiers };
@@ -0,0 +1,12 @@
1
+ export type SpecifierRewrite = (specifier: string) => string | undefined;
2
+ /**
3
+ * Rewrite the import/export/require specifiers of emitted JavaScript.
4
+ *
5
+ * Specifiers whose contents contain escape sequences are left untouched (the
6
+ * raw source slice would not round-trip), which never happens for the
7
+ * compiler-emitted relative/alias specifiers this is used on.
8
+ */
9
+ export declare const rewriteImportSpecifiers: (content: string, rewrite: SpecifierRewrite) => {
10
+ content: string;
11
+ changed: boolean;
12
+ };
@@ -1,2 +1,22 @@
1
1
  import type { CompileFunc } from '../../common';
2
+ type TsgoConfig = {
3
+ compilerOptions?: {
4
+ baseUrl?: unknown;
5
+ module?: string;
6
+ moduleResolution?: string;
7
+ noEmitOnError?: boolean;
8
+ outDir?: string;
9
+ rootDir?: string;
10
+ verbatimModuleSyntax?: boolean;
11
+ };
12
+ files?: string[];
13
+ include?: string[];
14
+ };
15
+ export declare const createResolvedTsgoConfig: (appDirectory: string, tsconfigPath: string, distDir: string, sourceDirs: string[], moduleType: 'module' | 'commonjs' | undefined, tsgoBinPath: string) => Promise<{
16
+ config: TsgoConfig;
17
+ resolvedConfigPath: string;
18
+ }>;
19
+ export declare const getTsgoBinPath: (appDirectory: string, resolvePaths?: string[]) => string;
20
+ export declare const rewriteOutputSpecifiers: (appDirectory: string, distDir: string, baseUrl: string, paths: Record<string, string[] | string>, moduleType?: 'module' | 'commonjs') => Promise<void>;
2
21
  export declare const compileByTs: CompileFunc;
22
+ export {};
@@ -1,3 +1,3 @@
1
1
  import type { MatchPath } from '@modern-js/utils/tsconfig-paths';
2
2
  export declare const createTsconfigPathsMatcher: (baseUrl: string, paths: Record<string, string[] | string>) => MatchPath | undefined;
3
- export declare function getNotAliasedPath(sourceFile: string, matcher: MatchPath, text: string, moduleType?: 'module' | 'commonjs'): any;
3
+ export declare function getNotAliasedPath(sourceFile: string, matcher: MatchPath, text: string, moduleType?: 'module' | 'commonjs'): string | undefined;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.2.0-ultramodern.99",
20
+ "version": "3.4.0-ultramodern.1",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
@@ -40,14 +40,22 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@swc/helpers": "^0.5.23",
43
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.99"
43
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.4.0-ultramodern.1"
44
44
  },
45
45
  "devDependencies": {
46
- "@rslib/core": "0.21.5",
47
- "@types/node": "^25.9.1",
48
- "@typescript/native-preview": "7.0.0-dev.20260527.2",
49
- "@scripts/rstest-config": "2.66.0",
50
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.99"
46
+ "@rslib/core": "0.23.0",
47
+ "@types/node": "^26.0.0",
48
+ "@typescript/native-preview": "7.0.0-dev.20260624.1",
49
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.4.0-ultramodern.1",
50
+ "@scripts/rstest-config": "2.66.0"
51
+ },
52
+ "peerDependencies": {
53
+ "@typescript/native-preview": ">=7.0.0-dev.20260624.1"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "@typescript/native-preview": {
57
+ "optional": true
58
+ }
51
59
  },
52
60
  "sideEffects": false,
53
61
  "publishConfig": {