Skip to content

Commit

Permalink
feat(web): add swc compiler option for webpack executor (nrwl#8114)
Browse files Browse the repository at this point in the history
jaysoo authored Dec 10, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 3bedfd8 commit f8c394a
Showing 27 changed files with 195 additions and 57 deletions.
10 changes: 10 additions & 0 deletions docs/angular/api-react/generators/application.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use class components instead of functional component.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Alias(es): dir
10 changes: 10 additions & 0 deletions docs/angular/api-web/executors/webpack.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use a separate bundle containing code used across multiple bundles.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### crossOrigin

Type: `string`
10 changes: 10 additions & 0 deletions docs/angular/api-web/generators/application.md
Original file line number Diff line number Diff line change
@@ -41,6 +41,16 @@ Type: `boolean`

Use babel instead ts-jest

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Type: `string`
10 changes: 10 additions & 0 deletions docs/node/api-react/generators/application.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use class components instead of functional component.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Alias(es): dir
10 changes: 10 additions & 0 deletions docs/node/api-web/executors/webpack.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use a separate bundle containing code used across multiple bundles.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### crossOrigin

Type: `string`
10 changes: 10 additions & 0 deletions docs/node/api-web/generators/application.md
Original file line number Diff line number Diff line change
@@ -41,6 +41,16 @@ Type: `boolean`

Use babel instead ts-jest

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Type: `string`
10 changes: 10 additions & 0 deletions docs/react/api-react/generators/application.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use class components instead of functional component.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Alias(es): dir
10 changes: 10 additions & 0 deletions docs/react/api-web/executors/webpack.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,16 @@ Type: `boolean`

Use a separate bundle containing code used across multiple bundles.

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### crossOrigin

Type: `string`
10 changes: 10 additions & 0 deletions docs/react/api-web/generators/application.md
Original file line number Diff line number Diff line change
@@ -41,6 +41,16 @@ Type: `boolean`

Use babel instead ts-jest

### compiler

Default: `babel`

Type: `string`

Possible values: `babel`, `swc`

The compiler to use

### directory

Type: `string`
2 changes: 1 addition & 1 deletion e2e/web/src/web.test.ts
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ describe('Web Components Applications', () => {
const appName = uniq('app');
const libName = uniq('lib');

runCLI(`generate @nrwl/web:app ${appName} --no-interactive`);
runCLI(`generate @nrwl/web:app ${appName} --no-interactive --compiler swc`);
runCLI(
`generate @nrwl/react:lib ${libName} --buildable --no-interactive --compiler swc`
);
16 changes: 16 additions & 0 deletions packages/react/src/generators/application/application.spec.ts
Original file line number Diff line number Diff line change
@@ -277,6 +277,7 @@ Object {
expect(targetConfig.build.executor).toEqual('@nrwl/web:webpack');
expect(targetConfig.build.outputs).toEqual(['{options.outputPath}']);
expect(targetConfig.build.options).toEqual({
compiler: 'babel',
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
index: 'apps/my-app/src/index.html',
main: 'apps/my-app/src/main.tsx',
@@ -735,4 +736,19 @@ Object {
).toBeTruthy();
});
});

describe('--compiler', () => {
it('should install swc packages if --compiler=swc', async () => {
await applicationGenerator(appTree, {
...schema,
compiler: 'swc',
});
const packageJson = readJson(appTree, '/package.json');

expect(packageJson.devDependencies).toMatchObject({
'@swc/core': expect.any(String),
'swc-loader': expect.any(String),
});
});
});
});
11 changes: 9 additions & 2 deletions packages/react/src/generators/application/application.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
extraEslintDependencies,
createReactEslintJson,
extraEslintDependencies,
} from '../../utils/lint';
import { NormalizedSchema, Schema } from './schema';
import { createApplicationFiles } from './lib/create-application-files';
@@ -24,6 +24,8 @@ import {
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import reactInitGenerator from '../init/init';
import { lintProjectGenerator } from '@nrwl/linter';
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
import { swcLoaderVersion } from '@nrwl/web/src/utils/versions';

async function addLinting(host: Tree, options: NormalizedSchema) {
const tasks: GeneratorCallback[] = [];
@@ -52,7 +54,12 @@ async function addLinting(host: Tree, options: NormalizedSchema) {
const installTask = await addDependenciesToPackageJson(
host,
extraEslintDependencies.dependencies,
extraEslintDependencies.devDependencies
{
...extraEslintDependencies.devDependencies,
...(options.compiler === 'swc'
? { '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion }
: {}),
}
);
tasks.push(installTask);

Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration {
outputs: ['{options.outputPath}'],
defaultConfiguration: 'production',
options: {
compiler: options.compiler ?? 'babel',
outputPath: joinPathFragments('dist', options.appProjectRoot),
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
baseHref: '/',
1 change: 1 addition & 0 deletions packages/react/src/generators/application/schema.d.ts
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ export interface Schema {
strict?: boolean;
setParserOptionsProject?: boolean;
standaloneConfig?: boolean;
compiler?: 'babel' | 'swc';
}

export interface NormalizedSchema extends Schema {
6 changes: 6 additions & 0 deletions packages/react/src/generators/application/schema.json
Original file line number Diff line number Diff line change
@@ -152,6 +152,12 @@
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean"
},
"compiler": {
"type": "string",
"description": "The compiler to use",
"enum": ["babel", "swc"],
"default": "babel"
}
},
"required": []
6 changes: 6 additions & 0 deletions packages/web/src/executors/webpack/schema.json
Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@
"type": "string",
"description": "The name of the Typescript configuration file."
},
"compiler": {
"type": "string",
"description": "The compiler to use",
"enum": ["babel", "swc"],
"default": "babel"
},
"outputPath": {
"type": "string",
"description": "The output path of the generated files."
14 changes: 13 additions & 1 deletion packages/web/src/executors/webpack/webpack.impl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ExecutorContext } from '@nrwl/devkit';
import { ExecutorContext, logger } from '@nrwl/devkit';
import type { Configuration, Stats } from 'webpack';
import { from, of } from 'rxjs';
import { bufferCount, mergeScan, switchMap, tap } from 'rxjs/operators';
@@ -132,6 +132,18 @@ export async function* run(

const metadata = context.workspace.projects[context.projectName];

if (options.compiler === 'swc') {
try {
require.resolve('swc-loader');
require.resolve('@swc/core');
} catch {
logger.error(
`Missing SWC dependencies: @swc/core, swc-loader. Make sure you install them first.`
);
return { success: false };
}
}

if (!options.buildLibsFromSource && context.targetName) {
const { dependencies } = calculateProjectDependencies(
readCachedProjectGraph(),
Original file line number Diff line number Diff line change
@@ -257,6 +257,7 @@ describe('app', () => {
expect(architectConfig.build.builder).toEqual('@nrwl/web:webpack');
expect(architectConfig.build.outputs).toEqual(['{options.outputPath}']);
expect(architectConfig.build.options).toEqual({
compiler: 'babel',
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
index: 'apps/my-app/src/index.html',
baseHref: '/',
13 changes: 13 additions & 0 deletions packages/web/src/generators/application/application.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
addDependenciesToPackageJson,
addProjectConfiguration,
convertNxGenerator,
formatFiles,
@@ -25,6 +26,8 @@ import { jestProjectGenerator } from '@nrwl/jest';

import { WebWebpackExecutorOptions } from '../../executors/webpack/webpack.impl';
import { Schema } from './schema';
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
import { swcLoaderVersion } from '../../utils/versions';

interface NormalizedSchema extends Schema {
projectName: string;
@@ -52,6 +55,7 @@ function addBuildTarget(
): ProjectConfiguration {
const buildOptions: WebWebpackExecutorOptions = {
outputPath: joinPathFragments('dist', options.appProjectRoot),
compiler: options.compiler ?? 'babel',
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
baseHref: '/',
main: joinPathFragments(options.appProjectRoot, 'src/main.ts'),
@@ -222,6 +226,15 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
tasks.push(jestTask);
}

if (options.compiler === 'swc') {
const installTask = await addDependenciesToPackageJson(
host,
{},
{ '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion }
);
tasks.push(installTask);
}

setDefaults(host, options);

if (!schema.skipFormat) {
1 change: 1 addition & 0 deletions packages/web/src/generators/application/schema.d.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ export interface Schema {
name: string;
prefix?: string;
style?: string;
compiler?: 'babel' | 'swc';
skipFormat?: boolean;
directory?: string;
tags?: string;
6 changes: 6 additions & 0 deletions packages/web/src/generators/application/schema.json
Original file line number Diff line number Diff line change
@@ -43,6 +43,12 @@
]
}
},
"compiler": {
"type": "string",
"description": "The compiler to use",
"enum": ["babel", "swc"],
"default": "babel"
},
"linter": {
"description": "The tool to use for running lint checks.",
"type": "string",
26 changes: 23 additions & 3 deletions packages/web/src/utils/config.ts
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ export function getBaseWebpackPartial(
fullySpecified: false,
},
},
{
options.compiler === 'babel' && {
test: /\.([jt])sx?$/,
loader: join(__dirname, 'web-babel-loader'),
exclude: /node_modules/,
@@ -87,7 +87,27 @@ export function getBaseWebpackPartial(
cacheCompression: false,
},
},
],
options.compiler === 'swc' && {
test: /\.([jt])sx?$/,
loader: require.resolve('swc-loader'),
exclude: /node_modules/,
options: {
jsc: {
parser: {
syntax: 'typescript',
decorators: true,
tsx: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
loose: true,
},
},
},
].filter(Boolean),
},
resolve: {
extensions,
@@ -123,7 +143,7 @@ export function getBaseWebpackPartial(
},
};

if (isScriptOptimizeOn) {
if (options.compiler !== 'swc' && isScriptOptimizeOn) {
webpackConfig.optimization = {
sideEffects: false,
minimizer: [
1 change: 1 addition & 0 deletions packages/web/src/utils/normalize.spec.ts
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ describe('normalizeBuildOptions', () => {

beforeEach(() => {
testOptions = {
compiler: 'babel',
main: 'apps/nodeapp/src/main.ts',
tsConfig: 'apps/nodeapp/tsconfig.app.json',
outputPath: 'dist/apps/nodeapp',
1 change: 1 addition & 0 deletions packages/web/src/utils/shared-models.ts
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ export interface OptimizationOptions {
export interface BuildBuilderOptions {
main: string;
outputPath: string;
compiler: 'babel' | 'swc';
tsConfig: string;
watch?: boolean;
sourceMap?: boolean | 'hidden';
1 change: 1 addition & 0 deletions packages/web/src/utils/versions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const nxVersion = '*';

export const swcLoaderVersion = '0.1.15';
export const sassVersion = '1.43.2';
50 changes: 1 addition & 49 deletions packages/web/src/utils/webpack/partials/common.ts
Original file line number Diff line number Diff line change
@@ -8,13 +8,11 @@ import { ExtraEntryPoint, WebpackConfigOptions } from '../../shared-models';
import { BuildBrowserFeatures } from '../build-browser-features';
import { getOutputHashFormat } from '../../hash-format';
import { normalizeExtraEntryPoints } from '../../normalize';
import CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
import { findAllNodeModules, findUp } from '../../fs';
import CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const TerserPlugin = require('terser-webpack-plugin');

// tslint:disable-next-line:no-big-function
export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
const { ContextReplacementPlugin } = webpack;

@@ -208,52 +206,6 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
);
}

if (scriptsOptimization) {
// TODO: Investigate why this fails for some packages: wco.supportES2015 ? 6 : 5;
const terserEcma = 5;

const terserOptions = {
warnings: !!buildOptions.verbose,
safari10: true,
output: {
ecma: terserEcma,
comments: false,
webkit: true,
},
// On server, we don't want to compress anything. We still set the ngDevMode = false for it
// to remove dev code, and ngI18nClosureMode to remove Closure compiler i18n code
compress: {
ecma: terserEcma,
// TODO(jack): Investigate options to enable further optimizations
// pure_getters: true,
// PURE comments work best with 3 passes.
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
// passes: 3,
},
mangle: true,
};

const es5TerserOptions = {
...terserOptions,
compress: {
...terserOptions.compress,
ecma: 5,
},
output: {
...terserOptions.output,
ecma: 5,
},
};

extraMinimizers.push(
new TerserPlugin({ terserOptions }),

// Script bundles are fully optimized here in one step since they are never downleveled.
// They are shared between ES2015 & ES5 outputs so must support ES5.
new TerserPlugin({ terserOptions: es5TerserOptions })
);
}

return {
mode:
scriptsOptimization || stylesOptimization ? 'production' : 'development',
5 changes: 4 additions & 1 deletion scripts/depcheck/missing.ts
Original file line number Diff line number Diff line change
@@ -90,7 +90,10 @@ const IGNORE_MATCHES = {
'@angular-devkit/architect',
],
web: [
'@swc/core', // we don't want to bloat the install of @nrwl/web by including @swc/core as a dependency.
// we don't want to bloat the install of @nrwl/web by including @swc/core and swc-loader as a dependency.
'@swc/core',
'swc-loader',

'fibers',
'node-sass',
],

0 comments on commit f8c394a

Please sign in to comment.