fix(react): update .swcrc with plugin for CSS-in-JS solution when SWC is used for apps (#17295)

This commit is contained in:
Jack Hsu 2023-05-30 01:33:08 -04:00 committed by GitHub
parent 4398932d0e
commit c8a264a932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 208 additions and 52 deletions

View File

@ -1,6 +1,7 @@
import {
convertNxGenerator,
formatFiles,
joinPathFragments,
runTasksInSerial,
Tree,
} from '@nx/devkit';
@ -36,7 +37,10 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
const lintTask = await addLinting(host, options);
updateJestConfig(host, options);
updateCypressTsConfig(host, options);
const styledTask = addStyleDependencies(host, options.style);
const styledTask = addStyleDependencies(host, {
style: options.style,
swc: !host.exists(joinPathFragments(options.appProjectRoot, '.babelrc')),
});
setDefaults(host, options);
if (options.customServer) {

View File

@ -2,6 +2,8 @@ import {
convertNxGenerator,
formatFiles,
getProjects,
joinPathFragments,
readProjectConfiguration,
runTasksInSerial,
Tree,
} from '@nx/devkit';
@ -37,6 +39,7 @@ function getDirectory(host: Tree, options: Schema) {
* extra dependencies for css, sass, less, styl style options.
*/
export async function componentGenerator(host: Tree, options: Schema) {
const project = readProjectConfiguration(host, options.project);
const componentInstall = await reactComponentGenerator(host, {
...options,
directory: getDirectory(host, options),
@ -45,7 +48,10 @@ export async function componentGenerator(host: Tree, options: Schema) {
skipFormat: true,
});
const styledInstall = addStyleDependencies(host, options.style);
const styledInstall = addStyleDependencies(host, {
style: options.style,
swc: !host.exists(joinPathFragments(project.root, '.babelrc')),
});
if (!options.skipFormat) {
await formatFiles(host);

View File

@ -2,6 +2,8 @@ import { componentGenerator as reactComponentGenerator } from '@nx/react';
import {
convertNxGenerator,
formatFiles,
joinPathFragments,
readProjectConfiguration,
runTasksInSerial,
Tree,
} from '@nx/devkit';
@ -15,6 +17,7 @@ import { Schema } from './schema';
* it is under `pages` folder.
*/
export async function pageGenerator(host: Tree, options: Schema) {
const project = readProjectConfiguration(host, options.project);
const directory = options.directory ? `pages/${options.directory}` : 'pages';
const componentTask = await reactComponentGenerator(host, {
...options,
@ -29,7 +32,10 @@ export async function pageGenerator(host: Tree, options: Schema) {
skipFormat: true,
});
const styledTask = addStyleDependencies(host, options.style);
const styledTask = addStyleDependencies(host, {
style: options.style,
swc: !host.exists(joinPathFragments(project.root, '.babelrc')),
});
if (!options.skipFormat) {
await formatFiles(host);

View File

@ -6,7 +6,10 @@ import {
} from '@nx/devkit';
import { lessVersion, stylusVersion } from '@nx/react/src/utils/versions';
import { CSS_IN_JS_DEPENDENCIES } from '@nx/react/src/utils/styled';
import {
cssInJsDependenciesBabel,
cssInJsDependenciesSwc,
} from '@nx/react/src/utils/styled';
import {
babelPluginStyledComponentsVersion,
emotionServerVersion,
@ -15,21 +18,7 @@ import {
stylusLoader,
} from './versions';
export const NEXT_SPECIFIC_STYLE_DEPENDENCIES = {
'styled-components': {
dependencies: CSS_IN_JS_DEPENDENCIES['styled-components'].dependencies,
devDependencies: {
...CSS_IN_JS_DEPENDENCIES['styled-components'].devDependencies,
'babel-plugin-styled-components': babelPluginStyledComponentsVersion,
},
},
'@emotion/styled': {
dependencies: {
...CSS_IN_JS_DEPENDENCIES['@emotion/styled'].dependencies,
'@emotion/server': emotionServerVersion,
},
devDependencies: CSS_IN_JS_DEPENDENCIES['@emotion/styled'].devDependencies,
},
const nextSpecificStyleDependenciesCommon = {
css: {
dependencies: {},
devDependencies: {},
@ -54,11 +43,50 @@ export const NEXT_SPECIFIC_STYLE_DEPENDENCIES = {
},
};
export const nextSpecificStyleDependenciesBabel = {
...nextSpecificStyleDependenciesCommon,
'styled-components': {
dependencies: cssInJsDependenciesBabel['styled-components'].dependencies,
devDependencies: {
...cssInJsDependenciesBabel['styled-components'].devDependencies,
'babel-plugin-styled-components': babelPluginStyledComponentsVersion,
},
},
'@emotion/styled': {
dependencies: {
...cssInJsDependenciesBabel['@emotion/styled'].dependencies,
'@emotion/server': emotionServerVersion,
},
devDependencies:
cssInJsDependenciesBabel['@emotion/styled'].devDependencies,
},
};
export const nextSpecificStyleDependenciesSwc = {
...nextSpecificStyleDependenciesCommon,
'styled-components': {
dependencies: cssInJsDependenciesSwc['styled-components'].dependencies,
devDependencies: {
...cssInJsDependenciesSwc['styled-components'].devDependencies,
'babel-plugin-styled-components': babelPluginStyledComponentsVersion,
},
},
'@emotion/styled': {
dependencies: {
...cssInJsDependenciesSwc['@emotion/styled'].dependencies,
'@emotion/server': emotionServerVersion,
},
devDependencies: cssInJsDependenciesSwc['@emotion/styled'].devDependencies,
},
};
export function addStyleDependencies(
host: Tree,
style: string
options: { style?: string; swc?: boolean }
): GeneratorCallback {
const extraDependencies = NEXT_SPECIFIC_STYLE_DEPENDENCIES[style];
const extraDependencies = options.swc
? nextSpecificStyleDependenciesSwc[options.style]
: nextSpecificStyleDependenciesBabel[options.style];
if (!extraDependencies) return () => {};
@ -70,7 +98,10 @@ export function addStyleDependencies(
// @zeit/next-less & @zeit/next-stylus internal configuration is working only
// for specific CSS loader version, causing PNPM resolution to fail.
if (host.exists('pnpm-lock.yaml') && (style === 'less' || style === 'styl')) {
if (
host.exists('pnpm-lock.yaml') &&
(options.style === 'less' || options.style === 'styl')
) {
updateJson(host, `package.json`, (json) => {
json.resolutions = { ...json.resolutions, 'css-loader': '1.0.1' };
return json;

View File

@ -2,7 +2,7 @@ export {
extraEslintDependencies,
extendReactEslintJson,
} from './src/utils/lint';
export { CSS_IN_JS_DEPENDENCIES } from './src/utils/styled';
export { cssInJsDependenciesBabel } from './src/utils/styled';
export { assertValidStyle } from './src/utils/assertion';
export { reactDomVersion, reactVersion } from './src/utils/versions';
export { applicationGenerator } from './src/generators/application/application';

View File

@ -205,7 +205,7 @@ export async function applicationGenerator(
updateSpecConfig(host, options);
const stylePreprocessorTask = installCommonDependencies(host, options);
tasks.push(stylePreprocessorTask);
const styledTask = addStyledModuleDependencies(host, options.styledModule);
const styledTask = addStyledModuleDependencies(host, options);
tasks.push(styledTask);
const routingTask = addRouting(host, options);
tasks.push(routingTask);

View File

@ -1,13 +0,0 @@
{
"presets": [
[
"@nx/react/babel", {
"runtime": "automatic"<% if (style === '@emotion/styled') { %>,<% } %>
<% if (style === '@emotion/styled') { %>"importSource": "@emotion/react" <% } %>
}
]
],
"plugins": [
<% if (style === 'styled-components') { %>["styled-components", { "pure": true, "ssr": true }]<% } %><% if (style === 'styled-jsx') { %>"styled-jsx/babel"<% } %><% if (style === '@emotion/styled') { %>"@emotion/babel-plugin"<% } %>
]
}

View File

@ -1,4 +1,11 @@
import { names, offsetFromRoot, Tree, toJS, generateFiles } from '@nx/devkit';
import {
generateFiles,
names,
offsetFromRoot,
toJS,
Tree,
writeJson,
} from '@nx/devkit';
import { getRelativePathToRootTsConfig } from '@nx/js';
import { join } from 'path';
import { createTsConfig } from '../../../utils/create-ts-config';
@ -34,16 +41,86 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
inSourceVitestTests: getInSourceVitestTestsTemplate(appTests),
};
let fileDirectory: string;
if (options.bundler === 'vite') {
fileDirectory = join(__dirname, '../files/base-vite');
generateFiles(
host,
join(__dirname, '../files/base-vite'),
options.appProjectRoot,
templateVariables
);
} else if (options.bundler === 'webpack') {
fileDirectory = join(__dirname, '../files/base-webpack');
} else if (options.bundler === 'rspack') {
fileDirectory = join(__dirname, '../files/base-rspack');
}
generateFiles(
host,
join(__dirname, '../files/base-webpack'),
options.appProjectRoot,
templateVariables
);
if (options.compiler === 'babel') {
writeJson(host, `${options.appProjectRoot}/.babelrc`, {
presets: [
[
'@nx/react/babel',
{
runtime: 'automatic',
importSource:
options.style === '@emotion/styled'
? '@emotion/react'
: undefined,
},
],
],
plugins: [
options.style === 'styled-components'
? ['styled-components', { pure: true, ssr: true }]
: undefined,
options.style === 'styled-jsx' ? 'styled-jsx/babel' : undefined,
options.style === '@emotion/styled'
? '@emotion/babel-plugin'
: undefined,
].filter(Boolean),
});
} else if (
options.style === 'styled-components' ||
options.style === '@emotion/styled' ||
options.style === 'styled-jsx'
) {
writeJson(
host,
`${options.appProjectRoot}/.swcrc`,
generateFiles(host, fileDirectory, options.appProjectRoot, templateVariables);
{
jsc: {
experimental: {
plugins: [
options.style === 'styled-components'
? [
'@swc/plugin-styled-components',
{
displayName: true,
ssr: true,
},
]
: undefined,
options.style === 'styled-jsx'
? ['@swc/plugin-styled-jsx', {}]
: undefined,
options.style === '@emotion/styled'
? ['@swc/plugin-emotion', {}]
: undefined,
].filter(Boolean),
},
},
}
);
}
} else if (options.bundler === 'rspack') {
generateFiles(
host,
join(__dirname, '../files/base-rspack'),
options.appProjectRoot,
templateVariables
);
}
if (
options.unitTestRunner === 'none' ||

View File

@ -30,7 +30,7 @@ export async function componentGenerator(host: Tree, schema: Schema) {
const tasks: GeneratorCallback[] = [];
const styledTask = addStyledModuleDependencies(host, options.styledModule);
const styledTask = addStyledModuleDependencies(host, options);
tasks.push(styledTask);
addExportsToBarrel(host, options);

View File

@ -1,8 +1,17 @@
import { CSS_IN_JS_DEPENDENCIES } from '../utils/styled';
import { addDependenciesToPackageJson, Tree } from '@nx/devkit';
import {
cssInJsDependenciesBabel,
cssInJsDependenciesSwc,
} from '../utils/styled';
export function addStyledModuleDependencies(host: Tree, styledModule: string) {
const extraDependencies = CSS_IN_JS_DEPENDENCIES[styledModule];
export function addStyledModuleDependencies(
host: Tree,
options: { styledModule?: string; compiler?: 'babel' | 'swc' }
) {
const extraDependencies =
options.compiler === 'swc'
? cssInJsDependenciesSwc[options.styledModule]
: cssInJsDependenciesBabel[options.styledModule];
if (extraDependencies) {
return addDependenciesToPackageJson(

View File

@ -6,14 +6,15 @@ import {
reactIsVersion,
styledComponentsVersion,
styledJsxVersion,
swcPluginEmotionVersion,
swcPluginStyledComponentsVersion,
swcPluginStyledJsxVersion,
typesReactIsVersion,
typesStyledComponentsVersion,
} from './versions';
import { PackageDependencies } from './dependencies';
export const CSS_IN_JS_DEPENDENCIES: {
[style: string]: PackageDependencies;
} = {
export const cssInJsDependenciesBabel: Record<string, PackageDependencies> = {
'styled-components': {
dependencies: {
'react-is': reactIsVersion,
@ -41,3 +42,34 @@ export const CSS_IN_JS_DEPENDENCIES: {
devDependencies: {},
},
};
export const cssInJsDependenciesSwc: Record<string, PackageDependencies> = {
'styled-components': {
dependencies: {
'react-is': reactIsVersion,
'styled-components': styledComponentsVersion,
},
devDependencies: {
'@types/styled-components': typesStyledComponentsVersion,
'@types/react-is': typesReactIsVersion,
'@swc/plugin-styled-components': swcPluginStyledComponentsVersion,
},
},
'@emotion/styled': {
dependencies: {
'@emotion/styled': emotionStyledVersion,
'@emotion/react': emotionReactVersion,
},
devDependencies: {
'@swc/plugin-emotion': swcPluginEmotionVersion,
},
},
'styled-jsx': {
dependencies: {
'styled-jsx': styledJsxVersion,
},
devDependencies: {
'@swc/plugin-styled-jsx': swcPluginStyledJsxVersion,
},
},
};

View File

@ -63,3 +63,7 @@ export const stylusVersion = '^0.55.0';
// rollup plugins (if needed)
export const rollupPluginUrlVersion = '^7.0.0';
export const svgrRollupVersion = '^8.0.1';
export const swcPluginStyledJsxVersion = '^1.5.67';
export const swcPluginEmotionVersion = '^2.5.67';
export const swcPluginStyledComponentsVersion = '^1.5.67';