diff --git a/packages/react/migrations.json b/packages/react/migrations.json index 75c272d617ad5..eb4c10017b1c5 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -53,6 +53,11 @@ "version": "14.0.0-beta.0", "description": "Add a default development configuration for build and serve targets.", "factory": "./src/migrations/update-14-0-0/add-default-development-configurations" + }, + "update-external-emotion-jsx-runtime-14.1.0": { + "version": "14.1.0-beta.0", + "description": "Update external option in projects for Emotion", + "factory": "./src/migrations/update-14-1-0/update-external-emotion-jsx-runtime" } }, "packageJsonUpdates": { diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index a5b804887ad47..b4c7b2637c235 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -560,7 +560,7 @@ describe('lib', () => { expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({ options: { - external: ['react/jsx-runtime', '@emotion/styled/base'], + external: ['@emotion/react/jsx-runtime'], }, }); expect(babelrc.plugins).toEqual(['@emotion/babel-plugin']); diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index 827ccb978480e..3c8c21c94db49 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -179,10 +179,12 @@ function addProject(host: Tree, options: NormalizedSchema) { if (options.publishable || options.buildable) { const { libsDir } = getWorkspaceLayout(host); - const external = ['react/jsx-runtime']; + const external: string[] = []; if (options.style === '@emotion/styled') { - external.push('@emotion/styled/base'); + external.push('@emotion/react/jsx-runtime'); + } else { + external.push('react/jsx-runtime'); } targets.build = { diff --git a/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.spec.ts b/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.spec.ts new file mode 100644 index 0000000000000..e3d77e14bfc37 --- /dev/null +++ b/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.spec.ts @@ -0,0 +1,64 @@ +import { + addProjectConfiguration, + readProjectConfiguration, +} from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import { updateExternalEmotionJsxRuntime } from './update-external-emotion-jsx-runtime'; + +describe('updateExternalEmotionJsxRuntime', () => { + it('should update external for Emotion', async () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(2); + addProjectConfiguration(tree, 'components', { + root: 'libs/components', + targets: { + build: { + executor: '@nrwl/web:rollup', + options: { + external: ['@emotion/styled/base', 'react/jsx-runtime'], + }, + }, + }, + }); + tree.write( + 'libs/components/.babelrc', + JSON.stringify({ + presets: [ + [ + '@nrwl/react/babel', + { + runtime: 'automatic', + importSource: '@emotion/react', + }, + ], + ], + plugins: ['@emotion/babel-plugin'], + }) + ); + + // ACT + await updateExternalEmotionJsxRuntime(tree); + + // ASSERT + const { targets } = readProjectConfiguration(tree, 'components'); + expect(targets.build.options.external).toEqual([ + '@emotion/react/jsx-runtime', + ]); + }); + + it('should not fail for projects with no targets', async () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(2); + addProjectConfiguration(tree, 'components', { + root: 'apps/components', + }); + + // ACT + await updateExternalEmotionJsxRuntime(tree); + + // ASSERT + const { targets } = readProjectConfiguration(tree, 'components'); + expect(targets).toBeUndefined(); + }); +}); diff --git a/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.ts b/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.ts new file mode 100644 index 0000000000000..cdb281943340f --- /dev/null +++ b/packages/react/src/migrations/update-14-1-0/update-external-emotion-jsx-runtime.ts @@ -0,0 +1,50 @@ +import { + Tree, + readProjectConfiguration, + updateProjectConfiguration, +} from '@nrwl/devkit'; +import { WebRollupOptions } from '@nrwl/web/src/executors/rollup/schema'; +import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; + +export async function updateExternalEmotionJsxRuntime(tree: Tree) { + forEachExecutorOptions( + tree, + '@nrwl/web:rollup', + (options: any, projectName, targetName, configurationName) => { + const projectConfiguration = readProjectConfiguration(tree, projectName); + const config = configurationName + ? projectConfiguration.targets[targetName].configurations[ + configurationName + ] + : projectConfiguration.targets[targetName].options; + + if (config.external && config.external.length > 0) { + const hasEmotionStyledBase = config.external.includes( + '@emotion/styled/base' + ); + const hasReactJsxRuntime = + config.external.includes('react/jsx-runtime'); + + if (hasEmotionStyledBase && hasReactJsxRuntime) { + // Replace 'react/jsx-runtime' with '@emotion/react/jsx-runtime' + config.external.forEach((value, index) => { + if (value === 'react/jsx-runtime') { + config.external.splice(index, 1, '@emotion/react/jsx-runtime'); + } + }); + + // Remove '@emotion/styled/base' + config.external.forEach((value, index) => { + if (value === '@emotion/styled/base') { + config.external.splice(index, 1); + } + }); + } + + updateProjectConfiguration(tree, projectName, projectConfiguration); + } + } + ); +} + +export default updateExternalEmotionJsxRuntime;