Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fastRefresh support anonymous default export function #6211

Merged
merged 15 commits into from
Mar 9, 2021
1 change: 0 additions & 1 deletion docs/docs/fast-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ Fast Refresh 功能最大的特性是:开发环境下,可以**保持组件

- Class 类组件一律重刷(remount),状态会被重置,包括高阶组件返回的 Class 组件
- 不纯组件模块,所编辑的模块除导出 React 组件外,还导出了其它模块
- 匿名箭头函数如 `export default () => <div />;` 会导致状态丢失
- 特殊的,还可以通过 `// @refresh reset` 指令(在源码文件中任意位置加上这行注释)强制重刷(remount),最大限度地保证可用性

## 技巧
Expand Down
1 change: 0 additions & 1 deletion docs/docs/fast-refresh.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Fast Refresh 功能最大的特性是:开发环境下,可以**保持组件

- Class 类组件一律重刷(remount),状态会被重置,包括高阶组件返回的 Class 组件
- 不纯组件模块,所编辑的模块除导出 React 组件外,还导出了其它模块
- 匿名箭头函数如 `export default () => <div />;` 会导致状态丢失
- 特殊的,还可以通过 `// @refresh reset` 指令(在源码文件中任意位置加上这行注释)强制重刷(remount),最大限度地保证可用性

## 技巧
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@testing-library/react": "^10.4.6",
"@types/babel__core": "7.1.9",
"@types/babel__traverse": "7.0.13",
"@types/dedent": "^0.7.0",
"@types/jest": "^26.0.4",
"@types/node": "^14.0.23",
"@umijs/core": "3.4.0-beta.6",
Expand All @@ -48,6 +49,7 @@
"@umijs/test-utils": "3.4.0-beta.6",
"@umijs/utils": "3.4.0-beta.6",
"benchmark": "^2.1.4",
"dedent": "^0.7.0",
"escape-goat": "^3.0.0",
"father-build": "^1.19.0",
"git-repo-info": "^2.1.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @umijs/babel-plugin-no-anonymous-default-export
30 changes: 30 additions & 0 deletions packages/babel-plugin-no-anonymous-default-export/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@umijs/babel-plugin-no-anonymous-default-export",
"version": "3.4.0-beta.6",
"description": "@umijs/babel-plugin-no-anonymous-default-export",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"src"
],
"repository": {
"type": "git",
"url": "https://github.com/umijs/umi"
},
"keywords": [
"umi"
],
"authors": [
"ycjcl868 <chaolinjin@gmail.com> (https://github.com/ycjcl868)"
],
"license": "MIT",
"bugs": "http://github.com/umijs/umi/issues",
"homepage": "https://github.com/umijs/umi/tree/master/packages/babel-plugin-no-anonymous-default-export#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@umijs/utils": "3.4.0-beta.6"
}
}
268 changes: 268 additions & 0 deletions packages/babel-plugin-no-anonymous-default-export/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import { transform } from '@babel/core';
import dedent from 'dedent';

function runPlugin(
code: string,
opts: { cwd: string; plugins?: any[]; filename: string },
) {
const res = transform(dedent`${code}`, {
babelrc: false,
sourceType: 'module',
presets: [
[
require.resolve('@babel/preset-react'),
{
development: true,
},
],
],
plugins: [[require.resolve('./index')]],
...opts,
});

if (!res) {
throw new Error('plugin failed');
}

return res;
}

test('normal arrow function', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/index.tsx',
};
expect(
runPlugin(
`
export default () => {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
const SrcIndex = () => {
return <p>Hello</p>;
};
export default SrcIndex;
`,
{ ...opts, plugins: [] },
).code,
);

// change filename
const componentOpts = {
cwd: '/a/b/c',
filename: '/a/b/c/components/About.tsx',
};
expect(
runPlugin(
`
export default () => {
return <p>Hello</p>;
};
`,
componentOpts,
).code,
).toEqual(
runPlugin(
`
const ComponentsAbout = () => {
return <p>Hello</p>;
};
export default ComponentsAbout;
`,
{ ...componentOpts, plugins: [] },
).code,
);
});

test('HOC not support', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/index.tsx',
};
expect(
runPlugin(
`
import { connect } from 'dva';

export default connect()(() => {
return <p>Hello</p>;
});
`,
opts,
).code,
).toEqual(
runPlugin(
`
import { connect } from 'dva';

export default connect()(() => {
return <p>Hello</p>;
});
`,
{ ...opts, plugins: [] },
).code,
);
});

test('normal anonymous function', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/index.tsx',
};
expect(
runPlugin(
`
export default function () {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
export default function SrcIndex() {
return <p>Hello</p>;
};
`,
{ ...opts, plugins: [] },
).code,
);
});

test('conflict declaration anonymous arrow function', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/index.tsx',
};
expect(
runPlugin(
`
function SrcIndex() {}

export default () => {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
function SrcIndex() {}

const SrcIndex0 = () => {
return <p>Hello</p>;
};

export default SrcIndex0;
`,
{ ...opts, plugins: [] },
).code,
);
});

test('conflict declaration anonymous function', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/index.tsx',
};
expect(
runPlugin(
`
function SrcIndex() {}

export default function () {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
function SrcIndex() {}

export default function SrcIndex0() {
return <p>Hello</p>;
};
`,
{ ...opts, plugins: [] },
).code,
);
});

test('no valid path', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/node_modules/antd/index.tsx',
};
const source = `
export default () => {
return <p>Hello</p>;
};
`;
expect(runPlugin(source, opts).code).toEqual(
runPlugin(source, { ...opts, plugins: [] }).code,
);
});

test('normal arrow function dynamic path', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/pages/[id].tsx',
};
expect(
runPlugin(
`
export default () => {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
const SrcPagesId = () => {
return <p>Hello</p>;
};
export default SrcPagesId;
`,
{ ...opts, plugins: [] },
).code,
);
});

test('with chinese name', () => {
const opts = {
cwd: '/a/b/c',
filename: '/a/b/c/src/pages/主页.tsx',
};
expect(
runPlugin(
`
export default () => {
return <p>Hello</p>;
};
`,
opts,
).code,
).toEqual(
runPlugin(
`
const SrcPages = () => {
return <p>Hello</p>;
};
export default SrcPages;
`,
{ ...opts, plugins: [] },
).code,
);
});
Loading