Skip to content

Commit

Permalink
feat: 在子进程执行
Browse files Browse the repository at this point in the history
  • Loading branch information
taojiahang.tjh committed Mar 21, 2024
1 parent 2e1ec79 commit 3ada245
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 99 deletions.
13 changes: 7 additions & 6 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,13 @@ function App() {
}
```

## forkTsChecker

- 类型:`boolean`
- 默认值:`false`

是否开启构建时 ts 校验。

## umd

- 类型:`false | string`
Expand All @@ -445,9 +452,3 @@ function App() {

是否在 mode 为 development 时将构建结果写入磁盘。

## tsChecker

- 类型:`boolean`
- 默认值:`false`

是否开启构建ts校验
12 changes: 6 additions & 6 deletions packages/bundler-okam/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const assert = require('assert');
const { createProxy, createHttpsServer } = require('@umijs/bundler-utils');
const lodash = require('lodash');
const chalk = require('chalk');
const { TypeChecker } = require('./plugins/fork-ts-checker/index');
const { ForkTsChecker } = require('./plugins/fork-ts-checker/index');
const {
createProxyMiddleware,
} = require('@umijs/bundler-utils/compiled/http-proxy-middleware');
Expand Down Expand Up @@ -101,9 +101,9 @@ exports.build = async function (opts) {
}

// 后置 ts 校验,不影响打包速度
if (!!okamConfig.tsChecker) {
const typeChecker = new TypeChecker(cwd);
typeChecker.check();
if (!!okamConfig.forkTsChecker) {
const forkTypeChecker = new ForkTsChecker(cwd);
forkTypeChecker.runTypeCheck();
}

const statsJsonPath = path.join(cwd, 'dist', 'stats.json');
Expand Down Expand Up @@ -474,7 +474,7 @@ async function getOkamConfig(opts) {
externals,
copy = [],
clean,
tsChecker,
forkTsChecker,
} = opts.config;
const outputPath = path.join(opts.cwd, 'dist');
// TODO:
Expand Down Expand Up @@ -603,7 +603,7 @@ async function getOkamConfig(opts) {
flexBugs: true,
react: opts.react || {},
emotion,
tsChecker,
forkTsChecker,
...(opts.disableCopy ? { copy: [] } : { copy: ['public'].concat(copy) }),
};

Expand Down
1 change: 0 additions & 1 deletion packages/bundler-okam/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"react-error-overlay": "6.0.9",
"react-refresh": "^0.14.0",
"rimraf": "5.0.1",
"typescript": "^5.4.2",
"webpack-5-chain": "8.0.1"
},
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// type-check-worker.js
const { TypeChecker } = require('./ts-checker'); // 确保这里的路径正确

const projectRoot = process.argv[2]; // 从命令行参数获取项目根目录

async function runTypeCheck() {
const typeChecker = new TypeChecker(projectRoot);
await typeChecker.check();
}

runTypeCheck()
.then(() => {
process.exit(0); // 成功完成
})
.catch((error) => {
console.error(error);
process.exit(1); // 发生错误
});
105 changes: 19 additions & 86 deletions packages/bundler-okam/plugins/fork-ts-checker/index.js
Original file line number Diff line number Diff line change
@@ -1,97 +1,30 @@
const ts = require('typescript');
const { fork } = require('child_process');
const path = require('path');
const fs = require('fs').promises;
const { TypeChecker } = require('./ts-checker'); // 确保这里的路径正确

class TypeChecker {
class ForkTsChecker {
constructor(projectRoot) {
this.projectRoot = projectRoot;
}
async runTypeCheck() {
const typeChecker = new TypeChecker(projectRoot);
await typeChecker.check();
}

async check() {
try {
const configPath = ts.findConfigFile(
this.projectRoot,
ts.sys.fileExists,
'tsconfig.json',
);
if (!configPath) {
console.error(
'Could not find a valid "tsconfig.json" file in the project root:',
this.projectRoot,
);
return;
}
let configFileText = '';
try {
configFileText = await fs.readFile(configPath, 'utf8');
} catch (readError) {
console.error(
`Error reading the "tsconfig.json" file at ${configPath}:`,
readError,
);
return;
}
const configFile = ts.parseConfigFileTextToJson(
configPath,
configFileText,
);
if (configFile.error) {
console.error('Error parsing "tsconfig.json" file:', configFile.error);
return;
}
let parsedCommandLine;
try {
parsedCommandLine = ts.parseJsonConfigFileContent(
configFile.config,
ts.sys,
path.dirname(configPath),
);
} catch (parseError) {
console.error(
'Error parsing the configuration from "tsconfig.json":',
parseError,
);
return;
}
let program;
try {
program = ts.createProgram({
rootNames: parsedCommandLine.fileNames,
options: { ...parsedCommandLine.options, noEmit: true },
});
} catch (programError) {
console.error('Error creating the TypeScript program:', programError);
return;
}
const diagnostics = ts.getPreEmitDiagnostics(program);
if (diagnostics.length > 0) {
diagnostics.forEach((diagnostic) => {
const message = ts.flattenDiagnosticMessageText(
diagnostic.messageText,
'\n',
);
if (diagnostic.file && typeof diagnostic.start === 'number') {
const { line, character } =
diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
console.error(
`${diagnostic.file.fileName} (${line + 1}, ${
character + 1
}): ${message}`,
);
} else {
console.error(message);
}
});
runTypeCheckInChildProcess() {
const workerScript = path.join(__dirname, 'child_process_fork.js'); // 确保这里的路径正确
const child = fork(workerScript, [projectRoot], {
stdio: 'inherit', // 继承标准输入输出,以便在主进程中看到输出
});

child.on('exit', (code) => {
if (code === 0) {
console.log('Type checking completed successfully.');
} else {
console.log('No type errors found.');
console.error('Type checking failed.');
}
} catch (error) {
console.error(
'An unexpected error occurred during type checking:',
error,
);
}
});
}
}

module.exports = { TypeChecker };
module.exports = { ForkTsChecker };
97 changes: 97 additions & 0 deletions packages/bundler-okam/plugins/fork-ts-checker/ts-checker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const ts = require('typescript');
const path = require('path');
const fs = require('fs').promises;

class TypeChecker {
constructor(projectRoot) {
this.projectRoot = projectRoot;
}

async check() {
try {
const configPath = ts.findConfigFile(
this.projectRoot,
ts.sys.fileExists,
'tsconfig.json',
);
if (!configPath) {
console.error(
'Could not find a valid "tsconfig.json" file in the project root:',
this.projectRoot,
);
return;
}
let configFileText = '';
try {
configFileText = await fs.readFile(configPath, 'utf8');
} catch (readError) {
console.error(
`Error reading the "tsconfig.json" file at ${configPath}:`,
readError,
);
return;
}
const configFile = ts.parseConfigFileTextToJson(
configPath,
configFileText,
);
if (configFile.error) {
console.error('Error parsing "tsconfig.json" file:', configFile.error);
return;
}
let parsedCommandLine;
try {
parsedCommandLine = ts.parseJsonConfigFileContent(
configFile.config,
ts.sys,
path.dirname(configPath),
);
} catch (parseError) {
console.error(
'Error parsing the configuration from "tsconfig.json":',
parseError,
);
return;
}
let program;
try {
program = ts.createProgram({
rootNames: parsedCommandLine.fileNames,
options: { ...parsedCommandLine.options, noEmit: true },
});
} catch (programError) {
console.error('Error creating the TypeScript program:', programError);
return;
}
const diagnostics = ts.getPreEmitDiagnostics(program);
if (diagnostics.length > 0) {
diagnostics.forEach((diagnostic) => {
const message = ts.flattenDiagnosticMessageText(
diagnostic.messageText,
'\n',
);
if (diagnostic.file && typeof diagnostic.start === 'number') {
const { line, character } =
diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
console.error(
`${diagnostic.file.fileName} (${line + 1}, ${
character + 1
}): ${message}`,
);
} else {
console.error(message);
}
});
} else {
console.log('No type errors found.');
}
} catch (error) {
console.error(
'An unexpected error occurred during type checking:',
error,
);
}
}
}

module.exports = { TypeChecker };

0 comments on commit 3ada245

Please sign in to comment.