Skip to content

Commit

Permalink
Merge pull request #2107 from nestjs/feat/swc-support
Browse files Browse the repository at this point in the history
feat: introduce swc support
  • Loading branch information
kamilmysliwiec committed Jun 14, 2023
2 parents 1e607ce + f36572f commit 8ef1a60
Show file tree
Hide file tree
Showing 26 changed files with 24,391 additions and 311 deletions.
177 changes: 135 additions & 42 deletions actions/build.action.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as chalk from 'chalk';
import { join } from 'path';
import { CompilerOptions } from 'typescript';
import { Input } from '../commands';
import { AssetsManager } from '../lib/compiler/assets-manager';
import { Compiler } from '../lib/compiler/compiler';
import { getValueOrDefault } from '../lib/compiler/helpers/get-value-or-default';
import { TsConfigProvider } from '../lib/compiler/helpers/tsconfig-provider';
import { PluginsLoader } from '../lib/compiler/plugins-loader';
import { PluginsLoader } from '../lib/compiler/plugins/plugins-loader';
import { SwcCompiler } from '../lib/compiler/swc/swc-compiler';
import { TypeScriptBinaryLoader } from '../lib/compiler/typescript-loader';
import { WatchCompiler } from '../lib/compiler/watch-compiler';
import { WebpackCompiler } from '../lib/compiler/webpack-compiler';
import { WorkspaceUtils } from '../lib/compiler/workspace-utils';
import {
Configuration,
ConfigurationLoader,
NestConfigurationLoader,
} from '../lib/configuration';
Expand All @@ -25,17 +26,6 @@ export class BuildAction extends AbstractAction {
protected readonly pluginsLoader = new PluginsLoader();
protected readonly tsLoader = new TypeScriptBinaryLoader();
protected readonly tsConfigProvider = new TsConfigProvider(this.tsLoader);
protected readonly compiler = new Compiler(
this.pluginsLoader,
this.tsConfigProvider,
this.tsLoader,
);
protected readonly webpackCompiler = new WebpackCompiler(this.pluginsLoader);
protected readonly watchCompiler = new WatchCompiler(
this.pluginsLoader,
this.tsConfigProvider,
this.tsLoader,
);
protected readonly fileSystemReader = new FileSystemReader(process.cwd());
protected readonly loader: ConfigurationLoader = new NestConfigurationLoader(
this.fileSystemReader,
Expand Down Expand Up @@ -90,13 +80,25 @@ export class BuildAction extends AbstractAction {
const { options: tsOptions } =
this.tsConfigProvider.getByConfigFilename(pathToTsconfig);
const outDir = tsOptions.outDir || defaultOutDir;

const isWebpackEnabled = getValueOrDefault<boolean>(
configuration,
'compilerOptions.webpack',
appName,
'webpack',
options,
);
const builder = isWebpackEnabled
? 'webpack'
: getValueOrDefault<'tsc' | 'swc' | 'webpack'>(
configuration,
'compilerOptions.builder',
appName,
'builder',
options,
'tsc',
);

await this.workspaceUtils.deleteOutDirIfEnabled(
configuration,
appName,
Expand All @@ -109,50 +111,141 @@ export class BuildAction extends AbstractAction {
watchAssetsMode,
);

if (isWebpackEnabled) {
const webpackPath = getValueOrDefault<string>(
configuration,
'compilerOptions.webpackConfigPath',
appName,
'webpackPath',
options,
);
switch (builder) {
case 'tsc':
return this.runTsc(
watchMode,
options,
configuration,
pathToTsconfig,
appName,
onSuccess,
);
case 'webpack':
return this.runWebpack(
configuration,
appName,
options,
pathToTsconfig,
isDebugEnabled,
watchMode,
onSuccess,
);
case 'swc':
return this.runSwc(
configuration,
appName,
pathToTsconfig,
watchMode,
options,
onSuccess,
);
}
}

const webpackConfigFactoryOrConfig = this.getWebpackConfigFactoryByPath(
webpackPath,
configuration.compilerOptions!.webpackConfigPath!,
);
return this.webpackCompiler.run(
configuration,
options,
private async runSwc(
configuration: Required<Configuration>,
appName: string,
pathToTsconfig: string,
watchMode: boolean,
options: Input[],
onSuccess: (() => void) | undefined,
) {
const swc = new SwcCompiler(this.pluginsLoader);
await swc.run(
configuration,
pathToTsconfig,
appName,
{
watch: watchMode,
typeCheck: getValueOrDefault<boolean>(
configuration,
'compilerOptions.typeCheck',
appName,
'typeCheck',
options,
),
},
onSuccess,
);
}

private runWebpack(
configuration: Required<Configuration>,
appName: string,
inputs: Input[],
pathToTsconfig: string,
debug: boolean,
watchMode: boolean,
onSuccess: (() => void) | undefined,
) {
const webpackCompiler = new WebpackCompiler(this.pluginsLoader);

const webpackPath = getValueOrDefault<string>(
configuration,
'compilerOptions.webpackConfigPath',
appName,
'webpackPath',
inputs,
);

const webpackConfigFactoryOrConfig = this.getWebpackConfigFactoryByPath(
webpackPath,
configuration.compilerOptions!.webpackConfigPath!,
);
return webpackCompiler.run(
configuration,
pathToTsconfig,
appName,
{
inputs,
webpackConfigFactoryOrConfig,
pathToTsconfig,
appName,
isDebugEnabled,
debug,
watchMode,
this.assetsManager,
onSuccess,
);
}
assetsManager: this.assetsManager,
},
onSuccess,
);
}

private runTsc(
watchMode: boolean,
options: Input[],
configuration: Required<Configuration>,
pathToTsconfig: string,
appName: string,
onSuccess: (() => void) | undefined,
) {
if (watchMode) {
const tsCompilerOptions: CompilerOptions = {};
const watchCompiler = new WatchCompiler(
this.pluginsLoader,
this.tsConfigProvider,
this.tsLoader,
);
const isPreserveWatchOutputEnabled = options.find(
(option) =>
option.name === 'preserveWatchOutput' && option.value === true,
);
if (isPreserveWatchOutputEnabled) {
tsCompilerOptions.preserveWatchOutput = true;
}
this.watchCompiler.run(
watchCompiler.run(
configuration,
pathToTsconfig,
appName,
tsCompilerOptions,
{ preserveWatchOutput: !!isPreserveWatchOutputEnabled },
onSuccess,
);
} else {
this.compiler.run(configuration, pathToTsconfig, appName, onSuccess);
const compiler = new Compiler(
this.pluginsLoader,
this.tsConfigProvider,
this.tsLoader,
);
compiler.run(
configuration,
pathToTsconfig,
appName,
undefined,
onSuccess,
);
this.assetsManager.closeWatchers();
}
}
Expand Down
34 changes: 33 additions & 1 deletion commands/build.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Command, CommanderStatic } from 'commander';
import { ERROR_PREFIX, INFO_PREFIX } from '../lib/ui';
import { AbstractCommand } from './abstract.command';
import { Input } from './command.input';

Expand All @@ -9,8 +10,13 @@ export class BuildCommand extends AbstractCommand {
.option('-c, --config [path]', 'Path to nest-cli configuration file.')
.option('-p, --path [path]', 'Path to tsconfig file.')
.option('-w, --watch', 'Run in watch mode (live-reload).')
.option('-b, --builder [name]', 'Builder to be used (tsc, webpack, swc).')
.option('--watchAssets', 'Watch non-ts (e.g., .graphql) files mode.')
.option('--webpack', 'Use webpack for compilation.')
.option(
'--webpack',
'Use webpack for compilation (deprecated option, use --build instead).',
)
.option('--type-check', 'Enable type checking (when SWC is used).')
.option('--webpackPath [path]', 'Path to webpack configuration.')
.option('--tsc', 'Use tsc for compilation.')
.description('Build Nest application.')
Expand All @@ -35,6 +41,32 @@ export class BuildCommand extends AbstractCommand {
value: command.webpackPath,
});

const availableBuilders = ['tsc', 'webpack', 'swc'];
if (command.builder && !availableBuilders.includes(command.builder)) {
console.error(
ERROR_PREFIX +
` Invalid builder option: ${
command.builder
}. Available builders: ${availableBuilders.join(', ')}`,
);
return;
}
options.push({
name: 'builder',
value: command.builder,
});

if (command.typeCheck && command.builder !== 'swc') {
console.warn(
INFO_PREFIX +
` "typeCheck" will not have any effect when "builder" is not "swc".`,
);
}
options.push({
name: 'typeCheck',
value: command.typeCheck,
});

const inputs: Input[] = [];
inputs.push({ name: 'app', value: app });
await this.action.handle(inputs, options);
Expand Down
34 changes: 33 additions & 1 deletion commands/start.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Command, CommanderStatic } from 'commander';
import { ERROR_PREFIX, INFO_PREFIX } from '../lib/ui';
import { getRemainingFlags } from '../lib/utils/remaining-flags';
import { AbstractCommand } from './abstract.command';
import { Input } from './command.input';
Expand All @@ -10,13 +11,18 @@ export class StartCommand extends AbstractCommand {
.option('-c, --config [path]', 'Path to nest-cli configuration file.')
.option('-p, --path [path]', 'Path to tsconfig file.')
.option('-w, --watch', 'Run in watch mode (live-reload).')
.option('-b, --builder [name]', 'Builder to be used (tsc, webpack, swc).')
.option('--watchAssets', 'Watch non-ts (e.g., .graphql) files mode.')
.option(
'-d, --debug [hostport] ',
'Run in debug mode (with --inspect flag).',
)
.option('--webpack', 'Use webpack for compilation.')
.option(
'--webpack',
'Use webpack for compilation (deprecated option, use --build instead).',
)
.option('--webpackPath [path]', 'Path to webpack configuration.')
.option('--type-check', 'Enable type checking (when SWC is used).')
.option('--tsc', 'Use tsc for compilation.')
.option(
'--sourceRoot [sourceRoot]',
Expand Down Expand Up @@ -73,6 +79,32 @@ export class StartCommand extends AbstractCommand {
!isWebpackEnabled,
});

const availableBuilders = ['tsc', 'webpack', 'swc'];
if (command.builder && !availableBuilders.includes(command.builder)) {
console.error(
ERROR_PREFIX +
` Invalid builder option: ${
command.builder
}. Available builders: ${availableBuilders.join(', ')}`,
);
return;
}
options.push({
name: 'builder',
value: command.builder,
});

if (command.typeCheck && command.builder !== 'swc') {
console.warn(
INFO_PREFIX +
` "typeCheck" will not have any effect when "builder" is not "swc".`,
);
}
options.push({
name: 'typeCheck',
value: command.typeCheck,
});

const inputs: Input[] = [];
inputs.push({ name: 'app', value: app });
const flags = getRemainingFlags(program);
Expand Down

0 comments on commit 8ef1a60

Please sign in to comment.