feat(react): support css prop for emotion (#7395)

* feat(react): support css prop for emotion

* feat(react): add migration for css prop
This commit is contained in:
Noriyuki Shinpuku 2021-10-18 11:17:16 +09:00 committed by GitHub
parent 7a3c485759
commit d4f8ba2b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 0 deletions

View File

@ -92,6 +92,12 @@
"version": "12.0.0-beta.0",
"description": "Remove @types/react-redux from package.json since react-redux installs the package automatically now",
"factory": "./src/migrations/update-12-0-0/remove-react-redux-types-package"
},
"update-emotion-setup-13.0.0": {
"cli": "nx",
"version": "13.0.0-beta.0",
"description": "Update tsconfig.json to use `jsxImportSource` to support css prop",
"factory": "./src/migrations/update-13-0-0/update-emotion-setup"
}
},
"packageJsonUpdates": {

View File

@ -537,6 +537,18 @@ Object {
expect(content).toContain('<StyledApp>');
});
it('should add jsxImportSource to tsconfig.json', async () => {
await applicationGenerator(appTree, {
...schema,
style: '@emotion/styled',
});
const tsconfigJson = readJson(appTree, 'apps/my-app/tsconfig.json');
expect(tsconfigJson.compilerOptions['jsxImportSource']).toEqual(
'@emotion/react'
);
});
it('should exclude styles from workspace.json', async () => {
await applicationGenerator(appTree, {
...schema,

View File

@ -2,6 +2,7 @@
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
<% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %>
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true

View File

@ -2,6 +2,7 @@
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
<% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %>
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true

View File

@ -488,6 +488,7 @@ describe('lib', () => {
const workspaceJson = readJson(appTree, '/workspace.json');
const babelrc = readJson(appTree, 'libs/my-lib/.babelrc');
const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.json');
expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({
options: {
@ -495,6 +496,9 @@ describe('lib', () => {
},
});
expect(babelrc.plugins).toEqual(['@emotion/babel-plugin']);
expect(tsconfigJson.compilerOptions['jsxImportSource']).toEqual(
'@emotion/react'
);
});
it('should support styled-jsx', async () => {

View File

@ -0,0 +1,90 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { readJson, Tree } from '@nrwl/devkit';
import { updateEmotionSetup } from './update-emotion-setup';
describe('Update tsconfig config for Emotion', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it(`should add jsxImportSource if it uses @emotion/react`, async () => {
tree.write(
'workspace.json',
JSON.stringify({
projects: {
'no-emotion-app': {
root: 'apps/no-emotion-app',
projectType: 'application',
},
'plain-react-app': {
root: 'apps/plain-react-app',
projectType: 'application',
},
'emotion-app': {
root: 'apps/emotion-app',
projectType: 'application',
},
},
})
);
tree.write(
'nx.json',
JSON.stringify({
projects: {
'no-emotion-app': {},
'plain-react-app': {},
'emotion-app': {},
},
})
);
tree.write('apps/no-emotion-app/.babelrc', JSON.stringify({}));
tree.write(
'apps/no-emotion-app/tsconfig.json',
JSON.stringify({ compilerOptions: {} })
);
tree.write(
'apps/plain-react-app/.babelrc',
JSON.stringify({
presets: ['@nrwl/react/babel'],
plugins: [],
})
);
tree.write(
'apps/plain-react-app/tsconfig.json',
JSON.stringify({ compilerOptions: { jsx: 'react-jsx' } })
);
tree.write(
'apps/emotion-app/.babelrc',
JSON.stringify({
presets: [
[
'@nrwl/react/babel',
{
runtime: 'automatic',
importSource: '@emotion/react',
},
],
],
plugins: ['@emotion/babel-plugin'],
})
);
tree.write(
'apps/emotion-app/tsconfig.json',
JSON.stringify({ compilerOptions: { jsx: 'react-jsx' } })
);
await updateEmotionSetup(tree);
expect(readJson(tree, 'apps/no-emotion-app/tsconfig.json')).toEqual({
compilerOptions: {},
});
expect(readJson(tree, 'apps/plain-react-app/tsconfig.json')).toEqual({
compilerOptions: { jsx: 'react-jsx' },
});
expect(readJson(tree, 'apps/emotion-app/tsconfig.json')).toEqual({
compilerOptions: { jsx: 'react-jsx', jsxImportSource: '@emotion/react' },
});
});
});

View File

@ -0,0 +1,42 @@
import {
formatFiles,
getProjects,
Tree,
readJson,
updateJson,
} from '@nrwl/devkit';
export async function updateEmotionSetup(host: Tree) {
const projects = getProjects(host);
projects.forEach((p) => {
let hasEmotion = false;
const babelrcPath = `${p.root}/.babelrc`;
const tsConfigPath = `${p.root}/tsconfig.json`;
if (host.exists(babelrcPath)) {
const babelrc = readJson(host, babelrcPath);
if (babelrc.presets) {
for (const [idx, preset] of babelrc.presets.entries()) {
if (Array.isArray(preset)) {
if (!preset[0].includes('@nrwl/react/babel')) continue;
const emotionOptions = preset[1];
hasEmotion = emotionOptions.importSource === '@emotion/react';
break;
}
}
}
}
if (hasEmotion && host.exists(tsConfigPath)) {
updateJson(host, tsConfigPath, (json) => {
json.compilerOptions.jsxImportSource = '@emotion/react';
return json;
});
}
});
await formatFiles(host);
}
export default updateEmotionSetup;