Skip to content

Commit

Permalink
fix: esbuild plugin break after stylable error (#2938)
Browse files Browse the repository at this point in the history
  • Loading branch information
barak007 committed Feb 11, 2024
1 parent e6ef253 commit 6199c02
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 11 deletions.
23 changes: 20 additions & 3 deletions packages/esbuild/src/stylable-esbuild-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,24 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi
build.onLoad(
{ filter: /.*/, namespace: namespaces.jsModule },
wrapDebug('onLoad stylable module', (args) => {
let res: StylableResults;
const cacheResults = checkCache(args.path);
if (cacheResults) {
return cacheResults;
}
onLoadCalled = true;

const res = stylable.transform(args.path);
try {
res = stylable.transform(args.path);
} catch (e) {
return {
errors: [
{
text: String(e),
},
],
watchFiles: [args.path],
};
}
const { errors, warnings } = esbuildEmitDiagnostics(res, diagnosticsMode);
const { imports, collector } = importsCollector(res);
const { cssDepth = 0, deepDependencies } = res.meta.transformCssDepth!;
Expand Down Expand Up @@ -316,7 +327,7 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi
* process the generated bundle and optimize the css output
*/
build.onEnd(
wrapDebug(`onEnd generate cssInjection: ${cssInjection}`, ({ metafile }) => {
wrapDebug(`onEnd generate cssInjection: ${cssInjection}`, ({ metafile, errors }) => {
transferBuildInfo();
if (!onLoadCalled) {
lazyDebugPrint();
Expand All @@ -326,6 +337,9 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi
let mapping: OptimizationMapping;
if (devTypes.enabled) {
if (!metafile) {
if (errors.length) {
return;
}
throw new Error('metafile is required for css injection');
}
const absSrcDir = join(projectRoot, devTypes.srcDir);
Expand Down Expand Up @@ -355,6 +369,9 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi

if (cssInjection === 'css') {
if (!metafile) {
if (errors.length) {
return;
}
throw new Error('metafile is required for css injection');
}
mapping ??= buildUsageMapping(metafile, stylable);
Expand Down
43 changes: 38 additions & 5 deletions packages/esbuild/test/e2e/esbuild-testkit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { dirname, join } from 'node:path';
import { readFileSync, symlinkSync, writeFileSync } from 'node:fs';
import { nodeFs } from '@file-services/node';
import { BuildContext, BuildOptions, context } from 'esbuild';
import { readFileSync, symlinkSync, writeFileSync, cpSync } from 'node:fs';

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / ubuntu-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / windows-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / macOS-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / ubuntu-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / windows-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / macOS-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / ubuntu-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / windows-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 18 / macOS-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / ubuntu-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / windows-latest

Module '"node:fs"' has no exported member 'cpSync'.

Check failure on line 2 in packages/esbuild/test/e2e/esbuild-testkit.ts

View workflow job for this annotation

GitHub Actions / node 16 / macOS-latest

Module '"node:fs"' has no exported member 'cpSync'.
import { BuildContext, BuildOptions, context, Plugin } from 'esbuild';
import { createTempDirectorySync, runServer } from '@stylable/e2e-test-kit';

import playwright from 'playwright-core';
Expand All @@ -21,11 +20,13 @@ export class ESBuildTestKit {
buildExport,
tmp = true,
overrideOptions = {},
extraPlugins = [],
}: {
project: string;
buildExport?: string;
tmp?: boolean;
overrideOptions?: BuildOptions;
extraPlugins?: Array<Plugin>;
}) {
let openServerUrl: string | undefined;
let buildFile = require.resolve(`@stylable/esbuild/test/e2e/${project}/build.js`);
Expand All @@ -34,7 +35,7 @@ export class ESBuildTestKit {
if (tmp) {
const t = createTempDirectorySync('esbuild-testkit');
this.disposables.push(() => t.remove());
nodeFs.copyDirectorySync(projectDir, t.path);
cpSync(projectDir, t.path, { recursive: true });
buildFile = join(t.path, 'build.js');
projectDir = t.path;

Expand All @@ -51,10 +52,41 @@ export class ESBuildTestKit {
if (!run) {
throw new Error(`could not find ${buildExport || 'run'} export in ${buildFile}`);
}
const onEnd = new Set<() => void>();
function act<T>(fn: () => T, timeout = 3000) {
return new Promise<T>((resolve, reject) => {
let results = undefined as T | Promise<T>;
const tm = setTimeout(reject, timeout);
const handler = () => {
clearTimeout(tm);
onEnd.delete(handler);
if (results instanceof Promise) {
results.then(resolve, reject);
} else {
resolve(results);
}
};
onEnd.add(handler);
results = fn();
});
}

const buildContext = await run(context, (options: BuildOptions) => ({
...options,
plugins: [...(options.plugins ?? [])],
plugins: [
...(options.plugins ?? []),
...extraPlugins,
{
name: 'build-end',
setup(build) {
build.onEnd(() => {
for (const fn of onEnd) {
fn();
}
});
},
},
],
absWorkingDir: projectDir,
loader: {
'.png': 'file',
Expand Down Expand Up @@ -124,6 +156,7 @@ export class ESBuildTestKit {
context: buildContext,
serve,
open,
act,
write(pathInCwd: string, content: string) {
writeFileSync(join(projectDir, pathInCwd), content, 'utf8');
},
Expand Down
26 changes: 23 additions & 3 deletions packages/esbuild/test/e2e/rebuild/rebuild.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,37 @@ describe('Stylable ESBuild plugin rebuild on change', () => {

afterEach(() => tk.dispose());

it('should pick up rebuild', async () => {
const { context, read, write } = await tk.build({
it('should pick up rebuild', async function () {
const { context, read, write, act } = await tk.build({
project: 'rebuild',
tmp: true,
});
const css1 = read('dist/index.js');
expect(css1, 'initial color').to.includes('color: red');
await context.watch();
await sleep(2222);
write('a.st.css', `.root{color: green}`);
await act(() => {
write('a.st.css', `.root{color: green}`);
});
const css2 = read('dist/index.js');
expect(css2, 'color after change').to.includes('color: green');
});

it('should stay alive after error', async function () {
const { context, read, write, act } = await tk.build({
project: 'rebuild',
tmp: true,
});
const css1 = read('dist/index.js');
expect(css1, 'initial color').to.includes('color: red');
await context.watch();
await sleep(2222);
await act(() => {
write('a.st.css', `.root{}}}}}`);
});
await act(() => {
write('a.st.css', `.root{color: green}`);
});
const css2 = read('dist/index.js');
expect(css2, 'color after change').to.includes('color: green');
});
Expand Down

0 comments on commit 6199c02

Please sign in to comment.