@modern-js/server-utils 2.4.1-beta.0 → 2.5.1-alpha.0

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.
@@ -0,0 +1,116 @@
1
+ import * as path from "path";
2
+ import {
3
+ getBabelChain,
4
+ applyUserBabelConfig
5
+ } from "@modern-js/babel-preset-lib";
6
+ import { fs, json5, getAliasConfig } from "@modern-js/utils";
7
+ import { compiler } from "@modern-js/babel-compiler";
8
+ import { FILE_EXTENSIONS } from "../../common";
9
+ export * from "@babel/core";
10
+ const readTsConfig = (tsconfigPath, noExistReturn = null) => {
11
+ if (!fs.existsSync(tsconfigPath)) {
12
+ return noExistReturn;
13
+ }
14
+ const content = fs.readFileSync(tsconfigPath, "utf-8");
15
+ return json5.parse(content);
16
+ };
17
+ const existTsConfigFile = (tsconfigAbsolutePath) => {
18
+ const tsconfig = readTsConfig(tsconfigAbsolutePath);
19
+ return Boolean(tsconfig);
20
+ };
21
+ const getBabelConfig = (libPresetOption, syntaxOption) => {
22
+ const chain = getBabelChain(libPresetOption, syntaxOption);
23
+ return {
24
+ sourceType: "unambiguous",
25
+ ...chain.toJSON()
26
+ };
27
+ };
28
+ const resolveBabelConfig = (appDirectory, config, option) => {
29
+ const { globalVars, alias, babelConfig, define } = config;
30
+ const globalDefineVars = define && Object.entries(define).reduce((object, [key, value]) => {
31
+ object[key] = JSON.stringify(value);
32
+ return object;
33
+ }, {});
34
+ const aliasConfig = getAliasConfig(alias, {
35
+ appDirectory,
36
+ ...option
37
+ });
38
+ const babelChain = getBabelChain(
39
+ {
40
+ appDirectory,
41
+ enableReactPreset: true,
42
+ enableTypescriptPreset: true,
43
+ alias: aliasConfig,
44
+ envVars: [],
45
+ globalVars: {
46
+ ...globalVars,
47
+ ...globalDefineVars
48
+ }
49
+ },
50
+ {
51
+ type: option.type,
52
+ syntax: option.syntax
53
+ }
54
+ );
55
+ const envOptions = babelChain.preset("@babel/preset-env").options();
56
+ babelChain.preset("@babel/preset-env").use(require.resolve("@babel/preset-env"), [
57
+ {
58
+ ...envOptions[0],
59
+ loose: true
60
+ }
61
+ ]);
62
+ babelChain.plugin("babel-plugin-transform-typescript-metadata").use(
63
+ require.resolve("babel-plugin-transform-typescript-metadata"),
64
+ []
65
+ );
66
+ babelChain.plugin("@babel/plugin-proposal-decorators").use(require.resolve("@babel/plugin-proposal-decorators"), [
67
+ { legacy: true }
68
+ ]);
69
+ babelChain.plugin("@babel/plugin-proposal-class-properties").use(require.resolve("@babel/plugin-proposal-class-properties"), [
70
+ {
71
+ loose: true
72
+ }
73
+ ]);
74
+ const internalBabelConfig = { ...babelChain.toJSON() };
75
+ return applyUserBabelConfig(internalBabelConfig, babelConfig);
76
+ };
77
+ const compileByBabel = async (appDirectory, config, compileOptions) => {
78
+ const { sourceDirs, distDir, tsconfigPath } = compileOptions;
79
+ const results = await Promise.all(
80
+ sourceDirs.map(async (sourceDir) => {
81
+ const babelConfig = resolveBabelConfig(appDirectory, config, {
82
+ tsconfigPath: tsconfigPath ? tsconfigPath : "",
83
+ syntax: "es6+",
84
+ type: "commonjs"
85
+ });
86
+ if (await fs.pathExists(sourceDir)) {
87
+ const basename = path.basename(sourceDir);
88
+ const targetDir = path.join(distDir, basename);
89
+ await fs.copy(sourceDir, targetDir, {
90
+ filter: (src) => ![".ts", ".js"].includes(path.extname(src)) && src !== tsconfigPath
91
+ });
92
+ }
93
+ return compiler(
94
+ {
95
+ rootDir: appDirectory,
96
+ distDir,
97
+ sourceDir,
98
+ extensions: FILE_EXTENSIONS
99
+ },
100
+ babelConfig
101
+ );
102
+ })
103
+ );
104
+ results.forEach((result) => {
105
+ if (result.code === 1) {
106
+ throw new Error(result.message);
107
+ }
108
+ });
109
+ };
110
+ export {
111
+ compileByBabel,
112
+ existTsConfigFile,
113
+ getBabelConfig,
114
+ readTsConfig,
115
+ resolveBabelConfig
116
+ };
@@ -0,0 +1,88 @@
1
+ import path from "path";
2
+ import { logger, getAliasConfig, fs } from "@modern-js/utils";
3
+ import ts from "typescript";
4
+ import { TypescriptLoader } from "./typescript-loader";
5
+ import { tsconfigPathsBeforeHookFactory } from "./tsconfig-paths-plugin";
6
+ const readTsConfigByFile = (tsConfigFile) => {
7
+ const parsedCmd = ts.getParsedCommandLineOfConfigFile(
8
+ tsConfigFile,
9
+ void 0,
10
+ ts.sys
11
+ );
12
+ const { options, fileNames, projectReferences } = parsedCmd;
13
+ return { options, fileNames, projectReferences };
14
+ };
15
+ const copyFiles = async (from, to, appDirectory, tsconfigPath) => {
16
+ if (await fs.pathExists(from)) {
17
+ const relativePath = path.relative(appDirectory, from);
18
+ const targetDir = path.join(to, relativePath);
19
+ await fs.copy(from, targetDir, {
20
+ filter: (src) => ![".ts"].includes(path.extname(src)) && src !== tsconfigPath
21
+ });
22
+ }
23
+ };
24
+ const compileByTs = async (appDirectory, config, compileOptions) => {
25
+ logger.info(`Running ts compile...`);
26
+ const { sourceDirs, distDir, tsconfigPath } = compileOptions;
27
+ if (!tsconfigPath) {
28
+ return;
29
+ }
30
+ const ts2 = new TypescriptLoader({
31
+ appDirectory
32
+ }).load();
33
+ const createProgram = ts2.createIncrementalProgram || ts2.createProgram;
34
+ const formatHost = getFormatHost(ts2);
35
+ const { alias } = config;
36
+ const aliasOption = getAliasConfig(alias, {
37
+ appDirectory,
38
+ tsconfigPath
39
+ });
40
+ const { paths = {}, absoluteBaseUrl = "./" } = aliasOption;
41
+ const { options, fileNames, projectReferences } = readTsConfigByFile(tsconfigPath);
42
+ const sourcePosixPaths = sourceDirs.map(
43
+ (sourceDir) => sourceDir.split(path.sep).join(path.posix.sep)
44
+ );
45
+ const rootNames = fileNames.filter((fileName) => {
46
+ return fileName.endsWith(".d.ts") || sourcePosixPaths.some((sourceDir) => {
47
+ return fileName.includes(sourceDir);
48
+ });
49
+ });
50
+ const program = createProgram.call(ts2, {
51
+ rootNames,
52
+ projectReferences,
53
+ options: {
54
+ rootDir: appDirectory,
55
+ outDir: distDir,
56
+ ...options
57
+ }
58
+ });
59
+ const tsconfigPathsPlugin = tsconfigPathsBeforeHookFactory(
60
+ ts2,
61
+ absoluteBaseUrl,
62
+ paths
63
+ );
64
+ const emitResult = program.emit(void 0, void 0, void 0, void 0, {
65
+ before: [tsconfigPathsPlugin]
66
+ });
67
+ const allDiagnostics = ts2.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
68
+ if (allDiagnostics.length > 0) {
69
+ logger.error(
70
+ ts2.formatDiagnosticsWithColorAndContext(allDiagnostics, formatHost)
71
+ );
72
+ process.exit(1);
73
+ }
74
+ for (const source of sourceDirs) {
75
+ await copyFiles(source, distDir, appDirectory, tsconfigPath);
76
+ }
77
+ logger.info(`Ts compile succeed`);
78
+ };
79
+ const getFormatHost = (ts2) => {
80
+ return {
81
+ getCanonicalFileName: (path2) => path2,
82
+ getCurrentDirectory: ts2.sys.getCurrentDirectory,
83
+ getNewLine: () => ts2.sys.newLine
84
+ };
85
+ };
86
+ export {
87
+ compileByTs
88
+ };
@@ -0,0 +1,187 @@
1
+ import * as os from "os";
2
+ import path, { dirname, posix } from "path";
3
+ import * as ts from "typescript";
4
+ import { createMatchPath } from "@modern-js/utils/tsconfig-paths";
5
+ const isRegExpKey = (str) => {
6
+ return str.startsWith("^") || str.endsWith("$");
7
+ };
8
+ const resolveAliasPath = (baseUrl, filePath) => {
9
+ if (filePath.startsWith(".") || filePath.startsWith("..")) {
10
+ return path.resolve(baseUrl, filePath);
11
+ }
12
+ return filePath;
13
+ };
14
+ const createAliasMatcher = (baseUrl, alias) => {
15
+ const aliasPairs = Object.keys(alias).reduce((o, key) => {
16
+ if (isRegExpKey(key)) {
17
+ const regexp = new RegExp(key);
18
+ const aliasPath = resolveAliasPath(baseUrl, alias[key]);
19
+ o.push([regexp, aliasPath]);
20
+ } else {
21
+ const aliasPath = resolveAliasPath(baseUrl, alias[key]);
22
+ o.push([key, aliasPath]);
23
+ }
24
+ return o;
25
+ }, []);
26
+ const cacheMap = /* @__PURE__ */ new Map();
27
+ return (requestedModule) => {
28
+ if (cacheMap.has(requestedModule)) {
29
+ return cacheMap.get(requestedModule);
30
+ }
31
+ for (const [key, value] of aliasPairs) {
32
+ if (key instanceof RegExp) {
33
+ if (key.test(requestedModule)) {
34
+ cacheMap.set(requestedModule, value);
35
+ return value;
36
+ }
37
+ }
38
+ if (requestedModule === key) {
39
+ cacheMap.set(requestedModule, value);
40
+ return value;
41
+ }
42
+ }
43
+ };
44
+ };
45
+ const isDynamicImport = (tsBinary, node) => {
46
+ return tsBinary.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;
47
+ };
48
+ function tsconfigPathsBeforeHookFactory(tsBinary, baseUrl, paths) {
49
+ const tsPaths = {};
50
+ const alias = {};
51
+ Object.keys(paths).forEach((key) => {
52
+ if (Array.isArray(paths[key])) {
53
+ tsPaths[key] = paths[key];
54
+ } else {
55
+ alias[key] = paths[key];
56
+ }
57
+ });
58
+ const matchAliasPath = createAliasMatcher(baseUrl, alias);
59
+ const matchTsPath = createMatchPath(baseUrl, tsPaths, ["main"]);
60
+ const matchPath = (requestedModule, readJSONSync, fileExists, extensions) => {
61
+ const result = matchTsPath(
62
+ requestedModule,
63
+ readJSONSync,
64
+ fileExists,
65
+ extensions
66
+ );
67
+ if (result) {
68
+ return result;
69
+ }
70
+ return matchAliasPath(requestedModule);
71
+ };
72
+ if (Object.keys(paths).length === 0) {
73
+ return void 0;
74
+ }
75
+ return (ctx) => {
76
+ return (sf) => {
77
+ const visitNode = (node) => {
78
+ var _a;
79
+ if (isDynamicImport(tsBinary, node)) {
80
+ const importPathWithQuotes = node.arguments[0].getText(sf);
81
+ const text = importPathWithQuotes.slice(
82
+ 1,
83
+ importPathWithQuotes.length - 1
84
+ );
85
+ const result = getNotAliasedPath(sf, matchPath, text);
86
+ if (!result) {
87
+ return node;
88
+ }
89
+ return tsBinary.factory.updateCallExpression(
90
+ node,
91
+ node.expression,
92
+ node.typeArguments,
93
+ tsBinary.factory.createNodeArray([
94
+ tsBinary.factory.createStringLiteral(result)
95
+ ])
96
+ );
97
+ }
98
+ if (tsBinary.isImportDeclaration(node) || tsBinary.isExportDeclaration(node) && node.moduleSpecifier) {
99
+ try {
100
+ const importPathWithQuotes = (_a = node == null ? void 0 : node.moduleSpecifier) == null ? void 0 : _a.getText();
101
+ if (!importPathWithQuotes) {
102
+ return node;
103
+ }
104
+ const text = importPathWithQuotes.substring(
105
+ 1,
106
+ importPathWithQuotes.length - 1
107
+ );
108
+ const result = getNotAliasedPath(sf, matchPath, text);
109
+ if (!result) {
110
+ return node;
111
+ }
112
+ const moduleSpecifier = tsBinary.factory.createStringLiteral(result);
113
+ moduleSpecifier.parent = node.moduleSpecifier.parent;
114
+ let newNode;
115
+ if (tsBinary.isImportDeclaration(node)) {
116
+ newNode = tsBinary.factory.updateImportDeclaration(
117
+ node,
118
+ node.decorators,
119
+ node.modifiers,
120
+ node.importClause,
121
+ moduleSpecifier,
122
+ node.assertClause
123
+ );
124
+ } else {
125
+ newNode = tsBinary.factory.updateExportDeclaration(
126
+ node,
127
+ node.decorators,
128
+ node.modifiers,
129
+ node.isTypeOnly,
130
+ node.exportClause,
131
+ moduleSpecifier,
132
+ node.assertClause
133
+ );
134
+ }
135
+ newNode.flags = node.flags;
136
+ return newNode;
137
+ } catch {
138
+ return node;
139
+ }
140
+ }
141
+ return tsBinary.visitEachChild(node, visitNode, ctx);
142
+ };
143
+ return tsBinary.visitNode(sf, visitNode);
144
+ };
145
+ };
146
+ }
147
+ function getNotAliasedPath(sf, matcher, text) {
148
+ let result = matcher(text, void 0, void 0, [
149
+ ".ts",
150
+ ".tsx",
151
+ ".js",
152
+ ".jsx"
153
+ ]);
154
+ if (!result) {
155
+ return;
156
+ }
157
+ if (os.platform() === "win32") {
158
+ result = result.replace(/\\/g, "/");
159
+ }
160
+ if (!path.isAbsolute(result)) {
161
+ if (!result.startsWith(".") && !result.startsWith("..")) {
162
+ try {
163
+ const packagePath = require.resolve(result, {
164
+ paths: [process.cwd(), ...module.paths]
165
+ });
166
+ if (packagePath) {
167
+ return result;
168
+ }
169
+ } catch {
170
+ }
171
+ }
172
+ try {
173
+ const packagePath = require.resolve(text, {
174
+ paths: [process.cwd(), ...module.paths]
175
+ });
176
+ if (packagePath) {
177
+ return text;
178
+ }
179
+ } catch {
180
+ }
181
+ }
182
+ const resolvedPath = posix.relative(dirname(sf.fileName), result) || "./";
183
+ return resolvedPath[0] === "." ? resolvedPath : `./${resolvedPath}`;
184
+ }
185
+ export {
186
+ tsconfigPathsBeforeHookFactory
187
+ };
@@ -0,0 +1,24 @@
1
+ class TypescriptLoader {
2
+ constructor({ appDirectory }) {
3
+ this.appDirectory = appDirectory;
4
+ }
5
+ load() {
6
+ if (this.tsBinary) {
7
+ return this.tsBinary;
8
+ }
9
+ try {
10
+ const tsPath = require.resolve("typescript", {
11
+ paths: [this.appDirectory || process.cwd()]
12
+ });
13
+ const ts = require(tsPath);
14
+ return ts;
15
+ } catch (error) {
16
+ throw new Error(
17
+ 'TypeScript could not be found! Please, install "typescript" package.'
18
+ );
19
+ }
20
+ }
21
+ }
22
+ export {
23
+ TypescriptLoader
24
+ };
@@ -0,0 +1,5 @@
1
+ export * from "./compilers/babel";
2
+ import { compile } from "./common";
3
+ export {
4
+ compile
5
+ };
package/package.json CHANGED
@@ -11,20 +11,19 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "2.4.1-beta.0",
14
+ "version": "2.5.1-alpha.0",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
- "main": "./dist/js/node/index.js",
18
- "module": "./dist/js/treeshaking/index.js",
19
- "jsnext:modern": "./dist/js/modern/index.js",
17
+ "main": "./dist/cjs/index.js",
18
+ "module": "./dist/esm/index.js",
20
19
  "exports": {
21
20
  ".": {
22
21
  "node": {
23
22
  "jsnext:source": "./src/index.ts",
24
- "import": "./dist/js/modern/index.js",
25
- "require": "./dist/js/node/index.js"
23
+ "import": "./dist/esm-node/index.js",
24
+ "require": "./dist/cjs/index.js"
26
25
  },
27
- "default": "./dist/js/treeshaking/index.js"
26
+ "default": "./dist/esm/index.js"
28
27
  }
29
28
  },
30
29
  "dependencies": {
@@ -34,22 +33,22 @@
34
33
  "@babel/preset-env": "^7.18.0",
35
34
  "@babel/preset-typescript": "^7.17.12",
36
35
  "@babel/runtime": "^7.18.0",
36
+ "@modern-js/babel-compiler": "2.5.0",
37
+ "@modern-js/babel-preset-lib": "2.5.0",
38
+ "@modern-js/utils": "2.5.0",
37
39
  "babel-plugin-module-resolver": "^4.1.0",
38
- "babel-plugin-transform-typescript-metadata": "^0.3.2",
39
- "@modern-js/babel-compiler": "2.4.1-beta.0",
40
- "@modern-js/babel-preset-lib": "2.4.1-beta.0",
41
- "@modern-js/utils": "2.4.1-beta.0"
40
+ "babel-plugin-transform-typescript-metadata": "^0.3.2"
42
41
  },
43
42
  "devDependencies": {
43
+ "@modern-js/server-core": "2.5.1-alpha.0",
44
+ "@scripts/build": "2.5.0",
45
+ "@scripts/jest-config": "2.5.0",
44
46
  "@types/babel__core": "^7.1.15",
45
47
  "@types/jest": "^27",
46
48
  "@types/node": "^14",
47
49
  "jest": "^27",
48
50
  "ts-jest": "^27.0.4",
49
- "typescript": "^4",
50
- "@modern-js/server-core": "2.4.1-beta.0",
51
- "@scripts/build": "2.4.0",
52
- "@scripts/jest-config": "2.4.0"
51
+ "typescript": "^4"
53
52
  },
54
53
  "sideEffects": false,
55
54
  "publishConfig": {