Skip to content

Commit

Permalink
add the compile task and use swc for non-watchmode builds
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanatkn committed Sep 19, 2020
1 parent ea4a264 commit ea9ff8b
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 26 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- add `swc` dependency along with a Rollup plugin and Svelte preprocessor
([#45](https://github.com/feltcoop/gro/pull/45))
- add the `compile` task and use `swc` for non-watchmode builds
([#46](https://github.com/feltcoop/gro/pull/46))

## 0.3.0

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"start": "gro",
"test": "gro test",
"bootstrap": "rm -rf build/ dist/ && tsc && cp -r build/ dist/ && npm link",
"preversion": "npm run bootstrap && gro check && npm run bootstrap && gro project/build"
"preversion": "npm run bootstrap && gro check && npm run bootstrap && NODE_ENV=production gro project/build"
},
"repository": {
"type": "git",
Expand Down
11 changes: 11 additions & 0 deletions src/compile.task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Task} from './task/task.js';
import {compile} from './compile/compile.js';
import {cleanBuild} from './project/clean.js';

export const task: Task = {
description: 'compiles all files to the build directory',
run: async ({log}) => {
await cleanBuild(log);
await compile(log);
},
};
90 changes: 90 additions & 0 deletions src/compile/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import swc from '@swc/core';
import {join} from 'path';

import {loadTsconfig} from './tsHelpers.js';
import {toSwcCompilerTarget, mergeSwcOptions, getDefaultSwcOptions} from './swcHelpers.js';
import {spawnProcess} from '../utils/process.js';
import {printMs, printPath, printSubTiming} from '../utils/print.js';
import {Logger} from '../utils/log.js';
import {Timings} from '../utils/time.js';
import {findFiles, outputFile, readFile} from '../fs/nodeFs.js';
import {paths, toBuildId} from '../paths.js';
import {red} from '../colors/terminal.js';

export const compile = async (log: Logger): Promise<void> => {
log.info('compiling...');

const timings = new Timings<'total'>();
timings.start('total');
const subTimings = new Timings();
const logTimings = () => {
for (const [key, timing] of subTimings.getAll()) {
log.trace(printSubTiming(key, timing));
}
log.info(`🕒 compiled in ${printMs(timings.stop('total'))}`);
};

if (process.env.NODE_ENV === 'production') {
await spawnProcess('node_modules/.bin/tsc'); // ignore compiler errors
logTimings();
return;
}

// load all files into memory
subTimings.start('find files');
const statsByPath = await findFiles(paths.source, ({path}) => path.endsWith('.ts'), null);
subTimings.stop('find files');
subTimings.start('read files');
const codeByPath = new Map<string, string>();
await Promise.all(
Array.from(statsByPath.entries()).map(async ([path, stats]) => {
if (stats.isDirectory()) return;
const contents = await readFile(join(paths.source, path), 'utf8');
// console.log('file', path, contents.length);
codeByPath.set(path, contents);
}),
);
subTimings.stop('read files');

// load the options
const tsconfigPath = undefined; // TODO parameterized options?
const basePath = undefined; // TODO parameterized options?
subTimings.start('load tsconfig');
const tsconfig = loadTsconfig(log, tsconfigPath, basePath);
subTimings.stop('load tsconfig');
const {compilerOptions} = tsconfig;
const target = toSwcCompilerTarget(compilerOptions && compilerOptions.target);
const swcOptions = getDefaultSwcOptions(); // TODO parameterized options?

const results = new Map<string, string>();

// compile everything
subTimings.start('compile');
await Promise.all(
Array.from(codeByPath.entries()).map(async ([path, code]) => {
const finalSwcOptions = mergeSwcOptions(swcOptions, target, path);

let output: swc.Output;
try {
// TODO maybe use the async version so we can preprocess in parallel?
output = await swc.transform(code, finalSwcOptions);
} catch (err) {
log.error(red('Failed to transpile TypeScript'), printPath(path));
throw err;
}

results.set(path, output.code);
results.set(`${path}.map`, output.map!);
}),
);
subTimings.stop('compile');

// output the compiled files
subTimings.start('write to disk');
await Promise.all(
Array.from(results.entries()).map(([path, contents]) => outputFile(toBuildId(path), contents)),
);
subTimings.stop('write to disk');

logTimings();
};
10 changes: 8 additions & 2 deletions src/project/swcHelpers.ts → src/compile/swcHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import swc from '@swc/core';
import {ScriptTarget} from 'typescript';
import {dirname, relative} from 'path';

import {toBuildId, toSourceId} from '../paths.js';

const DEFAULT_TARGET = 'es2019'; // TODO?

Expand Down Expand Up @@ -31,14 +34,14 @@ export const toSwcCompilerTarget = (target: ScriptTarget | undefined): swc.JscTa
export const mergeSwcOptions = (
options: swc.Options,
target: swc.JscTarget,
filename?: string,
path?: string,
): swc.Options => ({
...options,
jsc: {
...options.jsc,
target,
},
filename,
filename: path ? pathToSwcFilename(path) : undefined,
});

export const getDefaultSwcOptions = (): swc.Options => ({
Expand All @@ -49,3 +52,6 @@ export const getDefaultSwcOptions = (): swc.Options => ({
loose: true, // TODO?
},
});

const pathToSwcFilename = (path: string): string =>
relative(dirname(toBuildId(path)), toSourceId(path));
File renamed without changes.
1 change: 1 addition & 0 deletions src/docs/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ What is a task? See [`src/tasks/README.md`](../task).
- [build](../build.task.ts) - build the project
- [check](../check.task.ts) - check that everything is ready to commit
- [clean](../clean.task.ts) - remove build and temp files
- [compile](../compile.task.ts) - compiles all files to the build directory
- [deploy](../deploy.task.ts) - deploy to gh-pages
- [dev](../dev.task.ts) - start development server
- [dist](../dist.task.ts) - create the distribution
Expand Down
13 changes: 2 additions & 11 deletions src/project/build.task.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import {Task} from '../task/task.js';
import {spawnProcess} from '../utils/process.js';
import {cleanBuild} from './clean.js';

// TODO `process.env.NODE_ENV = 'production'`?
// set it where? what will it be used for?

export const task: Task = {
description: 'build, create, and link the distribution',
run: async ({log, invokeTask}) => {
await cleanBuild(log);

log.info('compiling typescript');
await spawnProcess('node_modules/.bin/tsc');

run: async ({invokeTask}) => {
await invokeTask('compile');
await invokeTask('project/dist');
},
};
4 changes: 2 additions & 2 deletions src/project/compilerBenchmark.task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ts from 'typescript';
import {join} from 'path';

import {Task} from '../task/task.js';
import {loadTsconfig} from './tsHelpers.js';
import {loadTsconfig} from '../compile/tsHelpers.js';
import {findFiles, readFile, outputFile} from '../fs/nodeFs.js';
import {paths} from '../paths.js';
import {printMs} from '../utils/print.js';
Expand Down Expand Up @@ -61,7 +61,7 @@ export const task: Task = {

const testFile = 'utils/json.ts';
const writeTestFile = async (suffix: string, contents: string, map = false) => {
await outputFile(`src/${testFile}.${suffix}.js${map ? '.map' : ''}`, contents, 'utf8');
await outputFile(`src/${testFile}.${suffix}.js${map ? '.map' : ''}`, contents);
};
const startBenchmark = (name: string) => {
log.info(name, '...');
Expand Down
7 changes: 3 additions & 4 deletions src/project/rollup-plugin-gro-swc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import {Plugin, PluginContext} from 'rollup';
import {resolve} from 'path';
import {createFilter} from '@rollup/pluginutils';

import {getDefaultSwcOptions, mergeSwcOptions, toSwcCompilerTarget} from './swcHelpers.js';
import {getDefaultSwcOptions, mergeSwcOptions, toSwcCompilerTarget} from '../compile/swcHelpers.js';
import {magenta, red} from '../colors/terminal.js';
import {createStopwatch} from '../utils/time.js';
import {SystemLogger, Logger} from '../utils/log.js';
import {printKeyValue, printMs, printPath} from '../utils/print.js';
import {toRootPath, isSourceId, toSourceExt} from '../paths.js';
import {loadTsconfig} from './tsHelpers.js';
import {loadTsconfig} from '../compile/tsHelpers.js';
import {omitUndefined} from '../utils/object.js';

// TODO improve along with Svelte compile stats
Expand Down Expand Up @@ -76,9 +76,8 @@ export const groSwcPlugin = (opts: InitialOptions = {}): Plugin => {
log.trace('transpile', printPath(id));
let output: swc.Output;
try {
const filename = id; // TODO convert to relative path?
// TODO keep this async, right?
const finalSwcOptions = mergeSwcOptions(swcOptions, target, filename);
const finalSwcOptions = mergeSwcOptions(swcOptions, target, id);
output = await swc.transform(code, finalSwcOptions);
} catch (err) {
log.error(red('Failed to transpile TypeScript'), printPath(id));
Expand Down
2 changes: 1 addition & 1 deletion src/project/rollup-plugin-gro-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {createStopwatch} from '../utils/time.js';
import {SystemLogger, Logger} from '../utils/log.js';
import {printKeyValue, printMs, printPath} from '../utils/print.js';
import {toRootPath, isSourceId, toSourceExt} from '../paths.js';
import {loadTsconfig, logTsDiagnostics} from './tsHelpers.js';
import {loadTsconfig, logTsDiagnostics} from '../compile/tsHelpers.js';
import {omitUndefined} from '../utils/object.js';

/*
Expand Down
4 changes: 2 additions & 2 deletions src/project/svelte-preprocess-swc.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import swc from '@swc/core';
import {PreprocessorGroup} from 'svelte/types/compiler/preprocess';

import {toSwcCompilerTarget, mergeSwcOptions, getDefaultSwcOptions} from './swcHelpers.js';
import {toSwcCompilerTarget, mergeSwcOptions, getDefaultSwcOptions} from '../compile/swcHelpers.js';
import {magenta, red} from '../colors/terminal.js';
import {SystemLogger} from '../utils/log.js';
import {loadTsconfig} from './tsHelpers.js';
import {loadTsconfig} from '../compile/tsHelpers.js';
import {printPath} from '../utils/print.js';
import {omitUndefined} from '../utils/object.js';

Expand Down
2 changes: 1 addition & 1 deletion src/project/svelte-preprocess-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {PreprocessorGroup} from 'svelte/types/compiler/preprocess';

import {magenta, red} from '../colors/terminal.js';
import {SystemLogger, Logger} from '../utils/log.js';
import {loadTsconfig} from './tsHelpers.js';
import {loadTsconfig} from '../compile/tsHelpers.js';
import {printPath} from '../utils/print.js';
import {omitUndefined} from '../utils/object.js';

Expand Down
4 changes: 2 additions & 2 deletions src/task/invokeTask.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {magenta, cyan, red, gray} from '../colors/terminal.js';
import {spawnProcess} from '../utils/process.js';
import {compile} from '../compile/compile.js';
import {Args} from '../cli/types';
import {SystemLogger, Logger} from '../utils/log.js';
import {runTask} from './runTask.js';
Expand Down Expand Up @@ -80,7 +80,7 @@ export const invokeTask = async (taskName: string, args: Args): Promise<void> =>
if (await shouldBuildProject(pathData)) {
log.info('Task file not found in build directory. Compiling TypeScript...');
subTimings.start('build project');
await spawnProcess('node_modules/.bin/tsc'); // ignore compiler errors
await compile(log);
subTimings.stop('build project');
}

Expand Down

0 comments on commit ea9ff8b

Please sign in to comment.