Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ It includes:
and Node servers/libraries, inspired by [Snowpack](https://github.com/pikapkg/snowpack)
- production bundling via [Rollup](https://github.com/rollup/rollup)
- fully integrated [TypeScript](https://github.com/microsoft/typescript)
using [swc](https://github.com/swc-project/swc) in dev mode for speed
using [esbuild](https://github.com/evanw/esbuild) in dev mode for speed
- [task runner](/src/task) that uses the filesystem convention `*.task.ts`
(docs at [`src/task`](/src/task))
- testing library called `oki` (docs at [`src/oki`](/src/oki))
Expand Down Expand Up @@ -140,7 +140,7 @@ Gro builds on
[Svelte](https://github.com/sveltejs/svelte) ∙
[Rollup](https://github.com/rollup/rollup) ∙
[TypeScript](https://github.com/microsoft/TypeScript) ∙
[swc](https://github.com/swc-project/swc) ∙
[esbuild](https://github.com/evanw/esbuild) ∙
[esinstall](https://github.com/snowpackjs/snowpack/tree/main/esinstall) ∙
[Prettier](https://github.com/prettier/prettier) ∙
[lukeed\/\*](https://github.com/lukeed) ∙
Expand Down
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
[#81](https://github.com/feltcoop/gro/pull/81),
[#88](https://github.com/feltcoop/gro/pull/88),
[#89](https://github.com/feltcoop/gro/pull/89))
- replace swc with esbuild
([#92](https://github.com/feltcoop/gro/pull/92))
- make `createBuilder` pluggable allowing users to provide a compiler for each file
([#57](https://github.com/feltcoop/gro/pull/57))
- rename `compiler` to `builder`
Expand Down
53 changes: 13 additions & 40 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
"scripts": {
"start": "gro",
"test": "gro test",
"bootstrap": "rm -rf .gro dist && tsc; cp -r .gro/prod/node/ dist/ && npm link",
"b": "npm run bootstrap",
"bootstrap": "rm -rf .gro dist && esbuild src/**/*.ts src/*.ts --outdir=.gro/prod/node/; cp -r .gro/prod/node/ dist/ && npm link",
"dev": "clear && rm -rf .gro && gro dev",
"d": "npm run dev",
"redev": "clear && npm run bootstrap && gro dev",
"r": "npm run redev",
"preversion": "npm run bootstrap && gro check && npm run bootstrap && gro project/build"
},
"repository": {
Expand Down Expand Up @@ -54,10 +51,10 @@
"@rollup/plugin-commonjs": "^16.0.0",
"@rollup/plugin-node-resolve": "^10.0.0",
"@rollup/pluginutils": "^4.0.0",
"@swc/core": "^1.2.28",
"cheap-watch": "^1.0.3",
"dequal": "^2.0.2",
"es-module-lexer": "^0.3.25",
"esbuild": "^0.9.2",
"esinstall": "^1.0.5",
"fs-extra": "^9.0.1",
"kleur": "^4.1.3",
Expand All @@ -68,7 +65,8 @@
"rollup": "^2.37.1",
"source-map-support": "^0.5.19",
"sourcemap-codec": "^1.4.8",
"svelte": "^3.29.0",
"svelte": "^3.31.0",
"svelte-preprocess-esbuild": "^2.0.0",
"terser": "^5.3.5",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
Expand Down
7 changes: 4 additions & 3 deletions src/build.task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {resolve} from 'path';
import {pathExists} from './fs/nodeFs.js';
import {Task} from './task/task.js';
import {createBuild} from './project/build.js';
import {getDefaultSwcOptions} from './build/swcBuildHelpers.js';
import {getDefaultEsbuildOptions} from './build/esbuildBuildHelpers.js';
import {loadTsconfig, toEcmaScriptTarget} from './build/tsBuildHelpers.js';

// TODO how should this be done? do we want to allow development builds with Rollup?
Expand All @@ -26,12 +26,13 @@ export const task: Task = {
const mapOutputOptions = args.mapOutputOptions as any;
const mapWatchOptions = args.mapWatchOptions as any;

// TODO this is outdated - needs to be updated with the Gro config (see `dev.task.ts`)
const tsconfigPath = undefined; // TODO parameterized options?
const basePath = undefined; // TODO parameterized options?
const tsconfig = loadTsconfig(log, tsconfigPath, basePath);
const target = toEcmaScriptTarget(tsconfig.compilerOptions?.target);
const sourceMap = tsconfig.compilerOptions?.sourceMap ?? process.env.NODE_ENV !== 'production';
const swcOptions = getDefaultSwcOptions(target, sourceMap);
const esbuildOptions = getDefaultEsbuildOptions(target, sourceMap);

if (inputFiles.length) {
const build = createBuild({
Expand All @@ -43,7 +44,7 @@ export const task: Task = {
mapInputOptions,
mapOutputOptions,
mapWatchOptions,
swcOptions,
esbuildOptions,
});
await build.promise;
} else {
Expand Down
5 changes: 0 additions & 5 deletions src/build/buildHelpers.ts

This file was deleted.

13 changes: 8 additions & 5 deletions src/build/defaultBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {SVELTE_EXTENSION, TS_EXTENSION} from '../paths.js';
import {Builder} from './builder.js';
import {createLazyBuilder, InitialOptions as LazyBuilderInitialOptions} from './lazyBuilder.js';
import {createSwcBuilder, InitialOptions as SwcBuilderInitialOptions} from './swcBuilder.js';
import {
createEsbuildBuilder,
InitialOptions as SwcBuilderInitialOptions,
} from './esbuildBuilder.js';
import {
createSvelteBuilder,
InitialOptions as SvelteBuilderInitialOptions,
Expand All @@ -13,16 +16,16 @@ import {
import {EXTERNALS_SOURCE_ID} from './externalsBuildHelpers.js';

export const createDefaultBuilder = (
swcBuilderOptions?: SwcBuilderInitialOptions,
esbuildBuilderOptions?: SwcBuilderInitialOptions,
svelteBuilderOptions?: SvelteBuilderInitialOptions,
externalsBuilderOptions?: ExternalsBuilderInitialOptions,
lazyBuilderOptions?: LazyBuilderInitialOptions,
): Builder => {
if (!lazyBuilderOptions?.getBuilder) {
const swcBuilder = createSwcBuilder(swcBuilderOptions);
const esbuildBuilder = createEsbuildBuilder(esbuildBuilderOptions);
const svelteBuilder = createSvelteBuilder(svelteBuilderOptions);
const externalsBuilder = createExternalsBuilder(externalsBuilderOptions);
const builders: Builder[] = [swcBuilder, svelteBuilder, externalsBuilder];
const builders: Builder[] = [esbuildBuilder, svelteBuilder, externalsBuilder];
lazyBuilderOptions = {
...lazyBuilderOptions,
getBuilder: (source, buildConfig) => {
Expand All @@ -34,7 +37,7 @@ export const createDefaultBuilder = (
}
switch (source.extension) {
case TS_EXTENSION:
return swcBuilder;
return esbuildBuilder;
case SVELTE_EXTENSION:
return svelteBuilder;
default:
Expand Down
29 changes: 29 additions & 0 deletions src/build/esbuildBuildHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import esbuild from 'esbuild';
import * as sveltePreprocessEsbuild from 'svelte-preprocess-esbuild';

import {DEFAULT_ECMA_SCRIPT_TARGET, EcmaScriptTarget} from './tsBuildHelpers.js';

export interface EsbuildTransformOptions extends esbuild.TransformOptions {
target: EcmaScriptTarget;
sourcemap: boolean;
}

export const getDefaultEsbuildOptions = (
target: EcmaScriptTarget = DEFAULT_ECMA_SCRIPT_TARGET,
sourcemap = true,
): EsbuildTransformOptions => ({
target,
sourcemap,
format: 'esm',
loader: 'ts',
tsconfigRaw: {compilerOptions: {importsNotUsedAsValues: 'remove'}},
});

export const getDefaultEsbuildPreprocessOptions = (
target: EcmaScriptTarget = DEFAULT_ECMA_SCRIPT_TARGET,
sourcemap = true,
): Partial<sveltePreprocessEsbuild.Options> => ({
target,
sourcemap,
tsconfigRaw: {compilerOptions: {}}, // pass an empty object so the preprocessor doesn't load the tsconfig
});
64 changes: 35 additions & 29 deletions src/build/swcBuilder.ts → src/build/esbuildBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,64 @@
import swc from '@swc/core';
import {relative} from 'path';
import esbuild from 'esbuild';

import {EcmaScriptTarget} from './tsBuildHelpers.js';
import {getDefaultSwcOptions} from './swcBuildHelpers.js';
import {getDefaultEsbuildOptions} from './esbuildBuildHelpers.js';
import {Logger, SystemLogger} from '../utils/log.js';
import {JS_EXTENSION, SOURCEMAP_EXTENSION, toBuildOutPath, TS_EXTENSION} from '../paths.js';
import {omitUndefined} from '../utils/object.js';
import type {Builder, BuildResult, TextBuild, TextBuildSource} from './builder.js';
import {replaceExtension} from '../utils/path.js';
import {cyan} from '../colors/terminal.js';
import {addJsSourceMapFooter} from './buildHelpers.js';
import {addJsSourceMapFooter} from './utils.js';

export interface Options {
log: Logger;
// TODO changes to this by consumers can break caching - how can the DX be improved?
createSwcOptions: CreateSwcOptions;
createEsbuildOptions: CreateEsbuildOptions;
}
export type InitialOptions = Partial<Options>;
export const initOptions = (opts: InitialOptions): Options => {
return {
createSwcOptions: createDefaultSwcOptions,
createEsbuildOptions: createDefaultEsbuildOptions,
...omitUndefined(opts),
log: opts.log || new SystemLogger([cyan('[swcBuilder]')]),
log: opts.log || new SystemLogger([cyan('[esbuildBuilder]')]),
};
};

type SwcBuilder = Builder<TextBuildSource, TextBuild>;
type EsbuildBuilder = Builder<TextBuildSource, TextBuild>;

export const createSwcBuilder = (opts: InitialOptions = {}): SwcBuilder => {
const {createSwcOptions} = initOptions(opts);
export const createEsbuildBuilder = (opts: InitialOptions = {}): EsbuildBuilder => {
const {createEsbuildOptions} = initOptions(opts);

const swcOptionsCache: Map<string, swc.Options> = new Map();
const getSwcOptions = (sourceMap: boolean, target: EcmaScriptTarget): swc.Options => {
const esbuildOptionsCache: Map<string, esbuild.TransformOptions> = new Map();
const getEsbuildOptions = (
sourceMap: boolean,
target: EcmaScriptTarget,
): esbuild.TransformOptions => {
const key = sourceMap + target;
const existingSwcOptions = swcOptionsCache.get(key);
if (existingSwcOptions !== undefined) return existingSwcOptions;
const newSwcOptions = createSwcOptions(sourceMap, target);
swcOptionsCache.set(key, newSwcOptions);
return newSwcOptions;
const existingEsbuildOptions = esbuildOptionsCache.get(key);
if (existingEsbuildOptions !== undefined) return existingEsbuildOptions;
const newEsbuildOptions = createEsbuildOptions(target, sourceMap);
esbuildOptionsCache.set(key, newEsbuildOptions);
return newEsbuildOptions;
};

const build: SwcBuilder['build'] = async (
const build: EsbuildBuilder['build'] = async (
source,
buildConfig,
{buildDir, dev, sourceMap, target},
) => {
if (source.encoding !== 'utf8') {
throw Error(`swc only handles utf8 encoding, not ${source.encoding}`);
throw Error(`esbuild only handles utf8 encoding, not ${source.encoding}`);
}
if (source.extension !== TS_EXTENSION) {
throw Error(`swc only handles ${TS_EXTENSION} files, not ${source.extension}`);
throw Error(`esbuild only handles ${TS_EXTENSION} files, not ${source.extension}`);
}
const {id, encoding, contents} = source;
const outDir = toBuildOutPath(dev, buildConfig.name, source.dirBasePath, buildDir);
const swcOptions = getSwcOptions(sourceMap, target);
const finalSwcOptions = {...swcOptions, filename: relative(outDir, id)};
const output = await swc.transform(contents, finalSwcOptions);
const esbuildOptions = {
...getEsbuildOptions(sourceMap, target),
sourcefile: source.id,
};
const output = await esbuild.transform(source.contents, esbuildOptions);
const jsFilename = replaceExtension(source.filename, JS_EXTENSION);
const jsId = `${outDir}${jsFilename}`;
const builds: TextBuild[] = [
Expand All @@ -64,7 +67,7 @@ export const createSwcBuilder = (opts: InitialOptions = {}): SwcBuilder => {
filename: jsFilename,
dir: outDir,
extension: JS_EXTENSION,
encoding,
encoding: source.encoding,
contents: output.map
? addJsSourceMapFooter(output.code, jsFilename + SOURCEMAP_EXTENSION)
: output.code,
Expand All @@ -78,7 +81,7 @@ export const createSwcBuilder = (opts: InitialOptions = {}): SwcBuilder => {
filename: jsFilename + SOURCEMAP_EXTENSION,
dir: outDir,
extension: SOURCEMAP_EXTENSION,
encoding,
encoding: source.encoding,
contents: output.map,
sourceMapOf: jsId,
buildConfig,
Expand All @@ -91,7 +94,10 @@ export const createSwcBuilder = (opts: InitialOptions = {}): SwcBuilder => {
return {build};
};

type CreateSwcOptions = (sourceMap: boolean, target: EcmaScriptTarget) => swc.Options;
type CreateEsbuildOptions = (
target: EcmaScriptTarget,
sourceMap: boolean,
) => esbuild.TransformOptions;

const createDefaultSwcOptions: CreateSwcOptions = (sourceMap, target) =>
getDefaultSwcOptions(target, sourceMap);
const createDefaultEsbuildOptions: CreateEsbuildOptions = (target, sourceMap) =>
getDefaultEsbuildOptions(target, sourceMap);
2 changes: 1 addition & 1 deletion src/build/externalsBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const createExternalsBuilder = (opts: InitialOptions = {}): ExternalsBuil
groSveltePlugin({
dev,
addCssBuild: addSvelteCssBuild,
preprocessor: createDefaultPreprocessor(sourceMap, target),
preprocessor: createDefaultPreprocessor(target, sourceMap),
compileOptions: {},
}),
];
Expand Down
2 changes: 1 addition & 1 deletion src/build/sourceMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const cleanSourceMeta = async (
let promises: Promise<void>[] | null = null;
for (const sourceId of sourceMetaBySourceId.keys()) {
if (!fileExists(sourceId) && !isExternalBrowserModule(sourceId)) {
log.warn('deleting unknown source meta', gray(sourceId));
log.trace('deleting unknown source meta', gray(sourceId));
(promises || (promises = [])).push(deleteSourceMeta(sourceMetaBySourceId, sourceId));
}
}
Expand Down
Loading