Skip to content

Commit

Permalink
feat: disable ts check for tmp files generated by api.writeTmpFile() (#…
Browse files Browse the repository at this point in the history
…4753)

* fix: preset-built-in types

* chore: types

* fix: default ignore plugins ts checker

* chore: docs

* chore: test case

* chore: other pr fix bundler type

* fix: rename tsNoCheck into skipTSCheck
  • Loading branch information
ycjcl868 committed May 25, 2020
1 parent 57b1a22 commit b896f13
Show file tree
Hide file tree
Showing 16 changed files with 138 additions and 23 deletions.
3 changes: 2 additions & 1 deletion docs/plugins/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,14 +493,15 @@ dev 退出时触发。

- 只针对 dev 命令有效

### writeTmpFile({ path: string, content: string })
### writeTmpFile({ path: string, content: string, skipTSCheck?: boolean })

写临时文件。

参数:

- `path`:相对于临时文件夹的路径
- `content`:文件内容
- `skipTSCheck`:默认为 `true``path` 为 ts 或 tsx 文件,不检查 TypeScript 类型错误,如果希望插件对用户项目进行 TypeScript 类型检查,可以设置为 `false`

注:

Expand Down
3 changes: 2 additions & 1 deletion docs/plugins/api.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,14 +493,15 @@ dev 退出时触发。

- 只针对 dev 命令有效

### writeTmpFile({ path: string, content: string })
### writeTmpFile({ path: string, content: string, skipTSCheck?: boolean })

写临时文件。

参数:

- `path`:相对于临时文件夹的路径
- `content`:文件内容
- `skipTSCheck`:默认为 `true``path` 为 ts 或 tsx 文件,不检查 TypeScript 类型错误,如果希望插件对用户项目进行 TypeScript 类型检查,可以设置为 `false`

注:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = (api) => {
api.registerCommand({
name: 'foo',
async fn() {
await api.applyPlugins({
key: 'onTestFoo',
type: 'event',
});
},
});

api.registerMethod({ name: 'onTestFoo' });

api.onTestFoo(() => {
api.writeTmpFile({
path: 'foo.ts',
content: 'foo',
skipTSCheck: false,
});
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = (api) => {
api.registerCommand({
name: 'foo',
async fn() {
await api.applyPlugins({
key: 'onTestFoo',
type: 'event',
});
},
});

api.registerMethod({ name: 'onTestFoo' });

api.onTestFoo(() => {
api.writeTmpFile({
path: 'foo.ts',
content: 'foo',
});
});
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

module.exports = (api) => {
api.registerCommand({
name: 'foo',
Expand Down
33 changes: 33 additions & 0 deletions packages/preset-built-in/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Service } from '@umijs/core';
import { Stream } from 'stream';
import { join } from 'path';
import { EOL } from 'os';
import cheerio from 'cheerio';
import { render, cleanup } from '@testing-library/react';
import { rimraf } from '@umijs/utils';
Expand Down Expand Up @@ -41,6 +42,38 @@ test('api.writeTmpFile', async () => {
rimraf.sync(tmpFile);
});

test('api.writeTmpFile with ts-nocheck', async () => {
const cwd = join(fixtures, 'api-writeTmpFile-ts');
const service = new Service({
cwd,
presets: [require.resolve('./index.ts')],
plugins: [require.resolve(join(cwd, 'plugin'))],
});
await service.run({
name: 'foo',
args: {},
});
const tmpFile = join(cwd, '.umi-test', 'foo.ts');
expect(readFileSync(tmpFile, 'utf-8')).toEqual(`// @ts-nocheck${EOL}foo`);
rimraf.sync(tmpFile);
});

test('api.writeTmpFile without ts-nocheck', async () => {
const cwd = join(fixtures, 'api-writeTmpFile-ts-check');
const service = new Service({
cwd,
presets: [require.resolve('./index.ts')],
plugins: [require.resolve(join(cwd, 'plugin'))],
});
await service.run({
name: 'foo',
args: {},
});
const tmpFile = join(cwd, '.umi-test', 'foo.ts');
expect(readFileSync(tmpFile, 'utf-8')).toEqual('foo');
rimraf.sync(tmpFile);
});

test('global js', async () => {
const cwd = join(fixtures, 'global-files');
const service = new Service({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function (api: IApi) {
return new Promise((resolve) => {
const interval = setInterval(() => {
if (
existsSync(join(api.paths!.absOutputPath, OUTPUT_SERVER_FILENAME))
existsSync(join(api.paths.absOutputPath!, OUTPUT_SERVER_FILENAME))
) {
clearInterval(interval);
resolve();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default function (api: IApi) {
if (process.env.RM_TMPDIR !== 'none') {
rimraf.sync(paths.absTmpPath!);
}
printFileSizes(stats, relative(process.cwd(), paths!.absOutputPath));
printFileSizes(stats, relative(process.cwd(), paths.absOutputPath!));
await api.applyPlugins({
key: 'onBuildComplete',
type: api.ApplyPluginsType.event,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { chokidar, signale, createDebug } from '@umijs/utils';
import { RequestHandler } from '@umijs/types';
import { RequestHandler, Request, Response, NextFunction } from '@umijs/types';
import { cleanRequireCache, IGetMockDataResult, matchMock } from './utils';

const debug = createDebug('umi:preset-build-in:mock:createMiddleware');
Expand Down Expand Up @@ -41,7 +41,7 @@ export default function (opts = {} as IMockOpts): ICreateMiddleware {
});

return {
middleware: (req, res, next) => {
middleware: (req: Request, res: Response, next: NextFunction) => {
const match = data && matchMock(req, data);
if (match) {
debug(`mock matched: [${match.method}] ${match.path}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IApi, RequestHandler, Request } from '@umijs/types';
import { IApi, RequestHandler, Request, NextFunction } from '@umijs/types';
import { winPath, createDebug, glob } from '@umijs/utils';
import { join } from 'path';
import { existsSync } from 'fs';
Expand Down Expand Up @@ -129,7 +129,7 @@ function parseKey(key: string) {
}

function createHandler(method: any, path: any, handler: any): RequestHandler {
return function (req, res, next) {
return function (req: Request, res: Response, next: NextFunction) {
if (BODY_PARSED_METHODS.includes(method)) {
bodyParser.json({ limit: '5mb', strict: false })(req, res, () => {
bodyParser.urlencoded({ limit: '5mb', extended: true })(
Expand Down
10 changes: 5 additions & 5 deletions packages/preset-built-in/src/plugins/features/exportStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export default (api: IApi) => {
const { exportStatic } = api.config;
// for dynamic routes
// TODO: test case
if (typeof exportStatic?.extraRoutePaths === 'function') {
const extraRoutePaths = await exportStatic?.extraRoutePaths();
if (exportStatic && typeof exportStatic.extraRoutePaths === 'function') {
const extraRoutePaths = await exportStatic.extraRoutePaths();
extraRoutePaths?.forEach((path) => {
const match = routeMap.find(({ route }: { route: IRoute }) => {
return route.path && pathToRegexp(route.path).exec(path);
Expand All @@ -86,15 +86,15 @@ export default (api: IApi) => {
api.modifyProdHTMLContent(async (memo, args) => {
const { route } = args;
const serverFilePath = join(
api.paths!.absOutputPath,
api.paths.absOutputPath!,
OUTPUT_SERVER_FILENAME,
);
const { ssr } = api.config;
if (
ssr &&
api.env === 'production' &&
existsSync(serverFilePath) &&
!isDynamicRoute(route!.path)
!isDynamicRoute(route.path!)
) {
try {
// do server-side render
Expand Down Expand Up @@ -123,7 +123,7 @@ export default (api: IApi) => {
if (!err && api.config?.ssr && process.env.RM_SERVER_FILE !== 'none') {
// remove umi.server.js
const serverFilePath = join(
api.paths!.absOutputPath,
api.paths.absOutputPath!,
OUTPUT_SERVER_FILENAME,
);
if (existsSync(serverFilePath)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/preset-built-in/src/plugins/features/ssr/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default (api: IApi) => {
// umi dev to enable server side render by default
const { stream, devServerRender = true } = api.config?.ssr || {};
const serverPath = path.join(
api.paths!.absOutputPath,
api.paths.absOutputPath!,
OUTPUT_SERVER_FILENAME,
);
// if dev clear cache
Expand Down Expand Up @@ -195,7 +195,7 @@ export default (api: IApi) => {
api.chainWebpack(async (config, opts) => {
const { paths } = api;
const { type } = opts;
const serverEntryPath = path.join(paths!.absTmpPath, 'core/server.ts');
const serverEntryPath = path.join(paths.absTmpPath!, 'core/server.ts');

if (type === BundlerConfigType.ssr) {
config.entryPoints.clear();
Expand Down
16 changes: 15 additions & 1 deletion packages/preset-built-in/src/plugins/registerMethods.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { IApi } from '@umijs/types';
import assert from 'assert';
import { EOL } from 'os';
import { dirname, join } from 'path';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { isTSFile } from './utils';

export default function (api: IApi) {
[
Expand Down Expand Up @@ -53,14 +55,26 @@ export default function (api: IApi) {

api.registerMethod({
name: 'writeTmpFile',
fn({ path, content }: { path: string; content: string }) {
fn({
path,
content,
skipTSCheck = true,
}: {
path: string;
content: string;
skipTSCheck?: boolean;
}) {
assert(
api.stage >= api.ServiceStage.pluginReady,
`api.writeTmpFile() should not execute in register stage.`,
);
const absPath = join(api.paths.absTmpPath!, path);
api.utils.mkdirp.sync(dirname(absPath));
if (!existsSync(absPath) || readFileSync(absPath, 'utf-8') !== content) {
if (isTSFile(path) && skipTSCheck) {
// write @ts-nocheck into first line
content = `// @ts-nocheck${EOL}${content}`;
}
writeFileSync(absPath, content, 'utf-8');
}
},
Expand Down
12 changes: 11 additions & 1 deletion packages/preset-built-in/src/plugins/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import { join } from 'path';
import { winPath } from '@umijs/utils';
import { getGlobalFile, isDynamicRoute } from './utils';
import { getGlobalFile, isDynamicRoute, isTSFile } from './utils';

test('getGlobalFile', () => {
const existsSyncMock = jest
Expand All @@ -25,3 +25,13 @@ test('isDynamicRoute', () => {
expect(isDynamicRoute(':id')).toBeTruthy();
expect(isDynamicRoute(undefined)).toBeFalsy();
});

test('isTSFile', () => {
expect(isTSFile('/bar/foo/a.js')).toEqual(false);
expect(isTSFile('/bar/foo/a')).toEqual(false);
expect(isTSFile('/bar/foo/a.ts')).toEqual(true);
expect(isTSFile('/bar/foo/a.tsx')).toEqual(true);
expect(isTSFile('/bar/foo/a.d.ts')).toEqual(false);
expect(isTSFile(undefined)).toEqual(false);
expect(isTSFile('/bar/foo.ts/a.js')).toEqual(false);
});
12 changes: 12 additions & 0 deletions packages/preset-built-in/src/plugins/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ export const getGlobalFile: IGetGlobalFile = ({ absSrcPath, files }) => {

export const isDynamicRoute = (path: string): boolean =>
!!path?.split('/')?.some?.((snippet) => snippet.startsWith(':'));

/**
* judge whether ts or tsx file exclude d.ts
* @param path
*/
export const isTSFile = (path: string): boolean => {
return (
typeof path === 'string' &&
!/\.d\.ts$/.test(path) &&
/\.(ts|tsx)$/.test(path)
);
};
14 changes: 9 additions & 5 deletions packages/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ type IPresetOrPlugin = string | [string, any];
type IBabelPresetOrPlugin = string | [string, any, string?];
type env = 'development' | 'production';

type IRouteMap = Array<{ route: Pick<IRoute, 'path'>; file: string }>;
interface IHtmlUtils extends Html {
getRouteMap: () => Promise<IRouteMap>;
}

export interface IApi extends PluginAPI {
// properties
paths: typeof Service.prototype.paths;
Expand All @@ -104,7 +109,9 @@ export interface IApi extends PluginAPI {
EnableBy: typeof Service.prototype.EnableBy;
stage: typeof Service.prototype.stage;
ServiceStage: typeof Service.prototype.ServiceStage;
writeTmpFile: { (args: { path: string; content: string }): void };
writeTmpFile: {
(args: { path: string; content: string; skipTSCheck?: boolean }): void;
};
registerGenerator: { (args: { key: string; Generator: Generator }): void };
babelRegister: typeof Service.prototype.babelRegister;
getRoutes: () => Promise<IRoute[]>;
Expand Down Expand Up @@ -194,10 +201,7 @@ export interface IApi extends PluginAPI {
}
>;
modifyDevHTMLContent: IModify<string | Stream, { req: Request }>;
modifyExportRouteMap: IModify<
{ route: Pick<IRoute, 'path'>; file: string }[],
{ html: InstanceType<Html> }
>;
modifyExportRouteMap: IModify<IRouteMap, { html: IHtmlUtils }>;
modifyProdHTMLContent: IModify<string, { route: IRoute; file: string }>;
chainWebpack: IModify<
WebpackChain,
Expand Down

0 comments on commit b896f13

Please sign in to comment.