Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: esbuild plugin break after stylable error (#2938) 5.x #2939

Merged
merged 2 commits into from
Feb 12, 2024
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
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
41 changes: 37 additions & 4 deletions packages/esbuild/test/e2e/esbuild-testkit.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
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 { BuildContext, BuildOptions, context, Plugin } from 'esbuild';
import { createTempDirectorySync, runServer } from '@stylable/e2e-test-kit';

import { nodeFs } from '@file-services/node';
import playwright from 'playwright-core';

type BuildFn = (
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 @@ -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
Loading