Skip to content
5 changes: 5 additions & 0 deletions .changeset/bundler-shutdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigtest/bundler": patch
---

The `try`/`finally` in `Bundler` was not wrapping the code that it should have; fix this by wrapping more.
5 changes: 5 additions & 0 deletions .changeset/manifest-builder-warnings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigtest/server": patch
---

Work around bug in node.js that throws warnings when using `fs.promises.truncate()`: https://github.com/nodejs/node/issues/34189
5 changes: 5 additions & 0 deletions .changeset/manifest-watcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigtest/bundler": patch
---

Properly ignore `node_modules` from `Bundler` file watcher.
25 changes: 15 additions & 10 deletions packages/bundler/src/bundler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Operation, resource } from 'effection';
import { on } from '@effection/events';
import { Subscribable, SymbolSubscribable } from '@effection/subscription';
import { subscribe, Subscribable, SymbolSubscribable, ChainableSubscription } from '@effection/subscription';
import { Channel } from '@effection/channel';
import { watch, RollupWatchOptions, RollupWatcherEvent } from 'rollup';
import { watch, RollupWatchOptions, RollupWatcherEvent, RollupWatcher } from 'rollup';
import resolve from '@rollup/plugin-node-resolve';
import * as commonjs from '@rollup/plugin-commonjs';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
Expand All @@ -28,6 +28,9 @@ export type BundlerMessage =
| { type: 'error'; error: BundlerError };

function prepareRollupOptions(bundles: Array<BundleOptions>, { mainFields }: BundlerOptions = { mainFields: ["browser", "main"] }): Array<RollupWatchOptions> {
// Rollup types are wrong; `watch.exclude` allows RegExp[]
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
return bundles.map(bundle => {
return {
input: bundle.entry,
Expand All @@ -38,7 +41,7 @@ function prepareRollupOptions(bundles: Array<BundleOptions>, { mainFields }: Bun
format: 'umd',
},
watch: {
exclude: ['node_modules/**']
exclude: [/node_modules/]
},
plugins: [
resolve({
Expand All @@ -64,16 +67,18 @@ export class Bundler implements Subscribable<BundlerMessage, undefined> {

static *create(bundles: Array<BundleOptions>): Operation<Bundler> {
let bundler = new Bundler();
let rollup = watch(prepareRollupOptions(bundles));
let events = Subscribable
.from(on<Array<RollupWatcherEvent>>(rollup, 'event'))
.map(([event]) => event)
.filter(event => event.code === 'END' || event.code === 'ERROR')
.map(event => event.code === 'ERROR' ? { type: 'error', error: event.error } : { type: 'update' });

return yield resource(bundler, function*() {
let rollup: RollupWatcher = watch(prepareRollupOptions(bundles));;

try {
yield events.forEach(function*(message) {
let events: ChainableSubscription<Array<RollupWatcherEvent>, undefined> = yield subscribe(on<Array<RollupWatcherEvent>>(rollup, 'event'));
let messages = events
.map(([event]) => event)
.filter(event => event.code === 'END' || event.code === 'ERROR')
.map(event => event.code === 'ERROR' ? { type: 'error', error: event.error } : { type: 'update' });

yield messages.forEach(function*(message) {
bundler.channel.send(message as BundlerMessage);
});
} finally {
Expand Down
39 changes: 33 additions & 6 deletions packages/server/src/manifest-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { bigtestGlobals } from '@bigtest/globals';
import { Operation } from 'effection';
import { once } from '@effection/events';
import { subscribe, ChainableSubscription } from '@effection/subscription';
import { Mailbox } from '@bigtest/effection';
import { Mailbox, Deferred } from '@bigtest/effection';
import { Bundler, BundlerMessage, BundlerError } from '@bigtest/bundler';
import { Atom } from '@bigtest/atom';
import { createFingerprint } from 'fprint';
Expand All @@ -14,7 +14,7 @@ import { Test } from '@bigtest/suite';

import { OrchestratorState } from './orchestrator/state';

const { copyFile, mkdir, truncate } = fs.promises;
const { copyFile, mkdir, stat, appendFile, open } = fs.promises;

interface ManifestBuilderOptions {
delegate: Mailbox;
Expand All @@ -24,14 +24,39 @@ interface ManifestBuilderOptions {
distDir: string;
};

function* ftruncate(fd: number, len: number): Operation<void> {
let { resolve, reject, promise } = Deferred<void>();

fs.ftruncate(fd, len, err => {
if (err) {
reject(err);
} else {
resolve();
}
});

yield promise;
}

// https://github.com/nodejs/node/issues/34189#issuecomment-654878715
function* truncate(path: string, len: number): Operation {
let file: fs.promises.FileHandle = yield open(path, 'r+');

try {
yield ftruncate(file.fd, len);
} finally {
file.close();
}
}

export function* updateSourceMapURL(filePath: string, sourcemapName: string): Operation{
let { size } = fs.statSync(filePath);
let { size } = yield stat(filePath);
let readStream = fs.createReadStream(filePath, {start: size - 16});
let [currentURL]: [Buffer] = yield once(readStream, 'data');

if (currentURL.toString().trim() === 'manifest.js.map') {
yield truncate(filePath, size - 16);
fs.appendFileSync(filePath, sourcemapName);
yield appendFile(filePath, sourcemapName);
} else {
throw new Error(`Expected a sourcemapping near the end of the generated test bundle, but found "${currentURL}" instead.`);
};
Expand Down Expand Up @@ -66,7 +91,9 @@ function* processManifest(options: ManifestBuilderOptions): Operation {

function logBuildError(error: BundlerError) {
console.error("[manifest builder] build error:", error.message);
console.error("[manifest builder] build error frame:\n", error.frame);
if (error.frame) {
console.error("[manifest builder] build error frame:\n", error.frame);
}
}

function* waitForSuccessfulBuild(bundlerEvents: ChainableSubscription<BundlerMessage, undefined>, delegate: Mailbox): Operation {
Expand Down Expand Up @@ -103,7 +130,7 @@ export function* createManifestBuilder(options: ManifestBuilderOptions): Operati
options.delegate.send({ event: "error" });
} else {
let distPath = yield processManifest(options);
console.debug("[manifest builder] manifest updated");
console.info("[manifest builder] manifest updated");
options.delegate.send({ event: "update", path: distPath });
}
});
Expand Down