diff --git a/docs/angular/api-react/generators/library.md b/docs/angular/api-react/generators/library.md index 3f04555dd840c7..83162864f0eccb 100644 --- a/docs/angular/api-react/generators/library.md +++ b/docs/angular/api-react/generators/library.md @@ -186,6 +186,14 @@ Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/s The file extension to be used for style files. +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### tags Alias(es): t diff --git a/docs/angular/api-web/executors/package.md b/docs/angular/api-web/executors/package.md index c275ab8fb5aada..6424c1915a82b8 100644 --- a/docs/angular/api-web/executors/package.md +++ b/docs/angular/api-web/executors/package.md @@ -108,6 +108,14 @@ Type: `array[] | string ` Path to a function which takes a rollup config and returns an updated rollup config +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### umdName Type: `string` diff --git a/docs/node/api-react/generators/library.md b/docs/node/api-react/generators/library.md index f215b96956558f..319e770dce58b4 100644 --- a/docs/node/api-react/generators/library.md +++ b/docs/node/api-react/generators/library.md @@ -186,6 +186,14 @@ Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/s The file extension to be used for style files. +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### tags Alias(es): t diff --git a/docs/node/api-web/executors/package.md b/docs/node/api-web/executors/package.md index 7e4729824605d4..17ddfeb8e3dd63 100644 --- a/docs/node/api-web/executors/package.md +++ b/docs/node/api-web/executors/package.md @@ -109,6 +109,14 @@ Type: `array[] | string ` Path to a function which takes a rollup config and returns an updated rollup config +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### umdName Type: `string` diff --git a/docs/react/api-react/generators/library.md b/docs/react/api-react/generators/library.md index f215b96956558f..319e770dce58b4 100644 --- a/docs/react/api-react/generators/library.md +++ b/docs/react/api-react/generators/library.md @@ -186,6 +186,14 @@ Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/s The file extension to be used for style files. +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### tags Alias(es): t diff --git a/docs/react/api-web/executors/package.md b/docs/react/api-web/executors/package.md index 7e4729824605d4..17ddfeb8e3dd63 100644 --- a/docs/react/api-web/executors/package.md +++ b/docs/react/api-web/executors/package.md @@ -109,6 +109,14 @@ Type: `array[] | string ` Path to a function which takes a rollup config and returns an updated rollup config +### swc + +Default: `false` + +Type: `boolean` + +Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking. + ### umdName Type: `string` diff --git a/e2e/react/src/react-package.test.ts b/e2e/react/src/react-package.test.ts index 337fc791cc700a..484cc03396a095 100644 --- a/e2e/react/src/react-package.test.ts +++ b/e2e/react/src/react-package.test.ts @@ -107,7 +107,7 @@ describe('Build React libraries and apps', () => { `generate @nrwl/react:library ${buildableChildLib} --buildable --no-interactive` ); runCLI( - `generate @nrwl/react:library ${buildableChildLib2} --buildable --no-interactive` + `generate @nrwl/react:library ${buildableChildLib2} --buildable --no-interactive --swc` ); createDep(buildableParentLib, [buildableChildLib, buildableChildLib2]); diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index b777d2e9aac921..84ab63dbe7ed55 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -1,4 +1,10 @@ -import { getProjects, readJson, Tree, updateJson } from '@nrwl/devkit'; +import { + getProjects, + readJson, + Tree, + updateJson, + readProjectConfiguration, +} from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import libraryGenerator from './library'; import { Linter } from '@nrwl/linter'; @@ -610,6 +616,34 @@ describe('lib', () => { }); }); + describe('--swc', () => { + it('should use SWC to build the library when --swc=true', async () => { + await libraryGenerator(appTree, { + ...defaultSchema, + buildable: true, + swc: true, + }); + + const packageJson = readJson(appTree, '/package.json'); + const config = readProjectConfiguration(appTree, 'my-lib'); + expect(packageJson.devDependencies['@swc/core']).toMatch( + /\^?\d+\.\d+\.\d+$/ + ); + expect(config.targets.build.options.swc).toBe(true); + }); + + it('should use SWC to build the library when --swc=false', async () => { + await libraryGenerator(appTree, { + ...defaultSchema, + buildable: true, + swc: false, + }); + + const config = readProjectConfiguration(appTree, 'my-lib'); + expect(config.targets.build.options.swc).not.toBeDefined(); + }); + }); + it.each` style ${'styled-components'} diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index d175f1957b8368..c6186eabf31ca6 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -1,24 +1,4 @@ -import { CSS_IN_JS_DEPENDENCIES } from '../../utils/styled'; - import * as ts from 'typescript'; -import { assertValidStyle } from '../../utils/assertion'; -import { - addBrowserRouter, - addInitialRoutes, - addRoute, - findComponentImportPath, -} from '../../utils/ast-utils'; -import { - extraEslintDependencies, - createReactEslintJson, -} from '../../utils/lint'; -import { - reactDomVersion, - reactRouterDomVersion, - reactVersion, - typesReactRouterDomVersion, -} from '../../utils/versions'; -import { Schema } from './schema'; import { addDependenciesToPackageJson, addProjectConfiguration, @@ -37,6 +17,25 @@ import { Tree, updateJson, } from '@nrwl/devkit'; +import { assertValidStyle } from '../../utils/assertion'; +import { + addBrowserRouter, + addInitialRoutes, + addRoute, + findComponentImportPath, +} from '../../utils/ast-utils'; +import { + createReactEslintJson, + extraEslintDependencies, +} from '../../utils/lint'; +import { + reactDomVersion, + reactRouterDomVersion, + reactVersion, + swcCoreVersion, + typesReactRouterDomVersion, +} from '../../utils/versions'; +import { Schema } from './schema'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import init from '../init/init'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; @@ -121,7 +120,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { react: reactVersion, 'react-dom': reactDomVersion, }, - {} + options.swc ? { '@swc/core': swcCoreVersion } : {} ); tasks.push(installTask); @@ -200,6 +199,10 @@ function addProject(host: Tree, options: NormalizedSchema) { ], }, }; + + if (options.swc) { + targets.build.options.swc = true; + } } addProjectConfiguration( diff --git a/packages/react/src/generators/library/schema.d.ts b/packages/react/src/generators/library/schema.d.ts index 2757f5f4bae4ad..454a4c773a222a 100644 --- a/packages/react/src/generators/library/schema.d.ts +++ b/packages/react/src/generators/library/schema.d.ts @@ -22,4 +22,5 @@ export interface Schema { strict?: boolean; setParserOptionsProject?: boolean; standaloneConfig?: boolean; + swc?: boolean; } diff --git a/packages/react/src/generators/library/schema.json b/packages/react/src/generators/library/schema.json index d4405e3f1f487c..c8b07a8f8e749e 100644 --- a/packages/react/src/generators/library/schema.json +++ b/packages/react/src/generators/library/schema.json @@ -155,6 +155,11 @@ "description": "Split the project configuration into /project.json rather than including it inside workspace.json", "type": "boolean", "default": false + }, + "swc": { + "description": "Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking.", + "type": "boolean", + "default": false } }, "required": ["name"] diff --git a/packages/react/src/utils/versions.ts b/packages/react/src/utils/versions.ts index d25d5031a7c32f..1a382a2ea02ecd 100644 --- a/packages/react/src/utils/versions.ts +++ b/packages/react/src/utils/versions.ts @@ -31,3 +31,5 @@ export const eslintPluginReactVersion = '7.23.1'; export const eslintPluginReactHooksVersion = '4.2.0'; export const babelPluginStyledComponentsVersion = '1.10.7'; + +export const swcCoreVersion = '^1.2.78'; diff --git a/packages/web/src/executors/package/lib/swc-plugin.ts b/packages/web/src/executors/package/lib/swc-plugin.ts new file mode 100644 index 00000000000000..a6a60cdfa9a150 --- /dev/null +++ b/packages/web/src/executors/package/lib/swc-plugin.ts @@ -0,0 +1,20 @@ +import { Plugin } from 'rollup'; + +export function swc(options = {}): Plugin { + try { + const { transform } = require('@swc/core'); + return { + name: 'nx-swc', + transform(code, filename) { + return transform(code, { + filename, + ...options, + }); + }, + }; + } catch { + throw new Error( + '"@swc/core" not installed in the workspace. Try `npm install --save-dev @swc/core` or `yarn add -D @swc/core`' + ); + } +} diff --git a/packages/web/src/executors/package/package.impl.ts b/packages/web/src/executors/package/package.impl.ts index d8c88ac11a9835..5ee3257c4b53a4 100644 --- a/packages/web/src/executors/package/package.impl.ts +++ b/packages/web/src/executors/package/package.impl.ts @@ -27,6 +27,7 @@ import { NormalizedWebPackageOptions, normalizePackageOptions, } from './lib/normalize'; +import { swc } from './lib/swc-plugin'; // These use require because the ES import isn't correct. const commonjs = require('@rollup/plugin-commonjs'); @@ -171,13 +172,6 @@ export function createRollupOptions( ), }), image(), - typescript({ - check: true, - tsconfig: options.tsConfig, - tsconfigOverride: { - compilerOptions: createCompilerOptions(format, options, dependencies), - }, - }), peerDepsExternal({ packageJsonPath: options.project, }), @@ -191,29 +185,43 @@ export function createRollupOptions( preferBuiltins: true, extensions: fileExtensions, }), - getBabelInputPlugin({ - // Let's `@nrwl/web/babel` preset know that we are packaging. - caller: { - // Ignored since this is for our custom babel-loader + babel preset - // @ts-ignore - isNxPackage: true, - }, - cwd: join(context.root, sourceRoot), - rootMode: 'upward', - babelrc: true, - extensions: fileExtensions, - babelHelpers: 'bundled', - exclude: /node_modules/, - plugins: [ - format === 'esm' - ? undefined - : require.resolve('babel-plugin-transform-async-to-promises'), - ].filter(Boolean), - }), + options.swc && swc(), + !options.swc && + typescript({ + check: true, + tsconfig: options.tsConfig, + tsconfigOverride: { + compilerOptions: createCompilerOptions( + format, + options, + dependencies + ), + }, + }), + !options.swc && + getBabelInputPlugin({ + // Let's `@nrwl/web/babel` preset know that we are packaging. + caller: { + // Ignored since this is for our custom babel-loader + babel preset + // @ts-ignore + isNxPackage: true, + }, + cwd: join(context.root, sourceRoot), + rootMode: 'upward', + babelrc: true, + extensions: fileExtensions, + babelHelpers: 'bundled', + exclude: /node_modules/, + plugins: [ + format === 'esm' + ? undefined + : require.resolve('babel-plugin-transform-async-to-promises'), + ].filter(Boolean), + }), commonjs(), filesize(), json(), - ]; + ].filter(Boolean); const globals = options.globals ? options.globals.reduce( diff --git a/packages/web/src/executors/package/schema.d.ts b/packages/web/src/executors/package/schema.d.ts index 5ea8199f49df69..a9489982de807d 100644 --- a/packages/web/src/executors/package/schema.d.ts +++ b/packages/web/src/executors/package/schema.d.ts @@ -20,4 +20,5 @@ export interface WebPackageOptions { umdName?: string; deleteOutputPath?: boolean; format: string[]; + swc?: boolean; } diff --git a/packages/web/src/executors/package/schema.json b/packages/web/src/executors/package/schema.json index b64343ebd4a53e..3b9f08e1cc616c 100644 --- a/packages/web/src/executors/package/schema.json +++ b/packages/web/src/executors/package/schema.json @@ -113,6 +113,11 @@ "items": { "$ref": "#/definitions/assetPattern" } + }, + "swc": { + "type": "boolean", + "description": "Use SWC to transpile code instead of Babel and TSC. Note that this will skip type-checking.", + "default": false } }, "required": ["tsConfig", "project", "entryFile", "outputPath"], diff --git a/scripts/check-versions.ts b/scripts/check-versions.ts index 9622091b5102a2..17c20e0ddd962d 100644 --- a/scripts/check-versions.ts +++ b/scripts/check-versions.ts @@ -24,9 +24,9 @@ const scoped = [ 'babel', 'emotion', 'reduxjs', + 'swc', 'testing-library', 'types', - 'zeit', ]; diff --git a/scripts/depcheck/missing.ts b/scripts/depcheck/missing.ts index ad23cf1feaffa5..69f9df8e0c89dd 100644 --- a/scripts/depcheck/missing.ts +++ b/scripts/depcheck/missing.ts @@ -73,7 +73,7 @@ const IGNORE_MATCHES = { '@angular-devkit/core', '@angular-devkit/architect', ], - web: ['fibers', 'node-sass'], + web: ['@swc/core', 'fibers', 'node-sass'], workspace: [ 'tslint', '@angular-devkit/architect',