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
17 changes: 14 additions & 3 deletions .github/workflows/check-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,20 @@ jobs:
- name: Start the lively server
run: |
chmod a+x ./start-server.sh
./start-server.sh > /dev/null 2>&1 &
# wait until server is guaranteed to be running
sleep 30
for attempt in 1 2 3; do
./start-server.sh > /tmp/lively-next-boot-server.log 2>&1 &
server_pid=$!
if node ./scripts/wait-for-server.js http://127.0.0.1:9011/ 120000 1000 "$server_pid"; then
exit 0
fi
echo "Lively server boot-check start attempt $attempt/3 failed. Recent server output:"
tail -80 /tmp/lively-next-boot-server.log 2>/dev/null || true
kill "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
pkill -f "bin/start-server.js.*9011" 2>/dev/null || true
pkill -f "start-server.sh" 2>/dev/null || true
done
exit 1
- name: Run boot check script
run: |
chmod a+x ./scripts/check-boot.sh
Expand Down
59 changes: 48 additions & 11 deletions flatn/bun-install.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execSync, spawnSync } from 'child_process';
import { execSync, spawn, spawnSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { gitSpecFromVersion } from './flatn-cjs.js';
Expand Down Expand Up @@ -77,16 +77,7 @@ export async function bunInstall (bunPath, livelyDirs, destDir, projectRoot, ver
);

// 4. Run bun install
const result = spawnSync(bunPath, ['install', '--no-progress'], {
cwd: bunWorkDir,
stdio: verbose ? 'inherit' : 'pipe',
env: { ...process.env }
});

if (result.status !== 0) {
const stderr = result.stderr ? result.stderr.toString() : '';
throw new Error(`bun install failed (exit ${result.status}): ${stderr}`);
}
await runBunInstall(bunPath, bunWorkDir, verbose);
// bun install completed

// 5. Build git spec map from original dependency version strings
Expand Down Expand Up @@ -137,6 +128,52 @@ export async function bunInstall (bunPath, livelyDirs, destDir, projectRoot, ver
return { newPackages };
}

async function runBunInstall (bunPath, bunWorkDir, verbose) {
console.log(' Running bun install...');

const child = spawn(bunPath, ['install', '--no-progress'], {
cwd: bunWorkDir,
stdio: verbose ? 'inherit' : ['ignore', 'pipe', 'pipe'],
env: { ...process.env }
});

let stdout = '';
let stderr = '';
let lastOutputAt = Date.now();
const startedAt = Date.now();

if (!verbose) {
child.stdout?.on('data', chunk => {
stdout += chunk.toString();
lastOutputAt = Date.now();
});
child.stderr?.on('data', chunk => {
stderr += chunk.toString();
lastOutputAt = Date.now();
});
}

const heartbeat = !verbose && setInterval(() => {
const elapsedSec = Math.round((Date.now() - startedAt) / 1000);
const quietSec = Math.round((Date.now() - lastOutputAt) / 1000);
console.log(` bun install still running... ${elapsedSec}s elapsed, ${quietSec}s since last output`);
}, 10000);

const result = await new Promise((resolve, reject) => {
child.on('error', reject);
child.on('close', (code, signal) => resolve({ code, signal }));
});

if (heartbeat) clearInterval(heartbeat);

if (result.code !== 0) {
const output = [stderr.trim(), stdout.trim()].filter(Boolean).join('\n');
throw new Error(
`bun install failed (${result.signal ? `signal ${result.signal}` : `exit ${result.code}`}): ${output}`
);
}
}

function buildGitDepMap (aggregatedDeps, bunWorkDir, bunPath) {
// Build a map of package name -> gitSpec using the ORIGINAL dependency version
// strings. This is critical because PackageSpec.matches() computes its gitSpec
Expand Down
2 changes: 1 addition & 1 deletion lively.changesets/src/changeset.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function adjustChangeSets (doFunc, doneFunc, skipPrev) { // (() -> Promise
const nextB = await targetBranchRead(pkg.address);
if (prevB && !nextB) {
console.log(`deactivating ${prevB}`);
prevB.deactivate();
await prevB.deactivate();
} else if (!prevB && nextB || prevB && nextB && prevB.name !== nextB.name) {
console.log(`activating ${nextB}`);
await nextB.activate();
Expand Down
4 changes: 3 additions & 1 deletion lively.changesets/tests/changeset-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import changeSet, { localChangeSets } from '../src/changeset.js';
import { pkgDir, fileA, createPackage, deletePackage, initTestChangeSet } from './helpers.js';
import { install, uninstall } from 'lively.changesets';

describe('changesets', () => {
describe('changesets', function () {
this.timeout(5000);

beforeEach(async () => {
install();
await createPackage();
Expand Down
4 changes: 3 additions & 1 deletion lively.changesets/tests/serialization-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { module } from 'lively.modules';
import { importChangeSet, localChangeSets } from '../src/changeset.js';
import { fileA, createPackage, deletePackage, initTestChangeSet } from './helpers.js';

describe('serialize', () => {
describe('serialize', function () {
this.timeout(5000);

let cs;
beforeEach(async () => {
await createPackage();
Expand Down
6 changes: 4 additions & 2 deletions lively.classes/tests/object-class-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ let S, opts, packagesToRemove;
describe('object package', function () {
beforeEach(async () => {
S = getSystem('test', { baseURL: testBaseURL });
S.set('lively.transpiler.babel', System.get('lively.transpiler.babel'));
S.config({ transpiler: 'lively.transpiler.babel' });
const transpiler = System.transpiler;
S.set(transpiler, System.get(transpiler));
S.config({ transpiler });
S._loader.transpilerPromise = System._loader.transpilerPromise;
S.translate = async (load, opts) => await System.translate.bind(S)(load, opts);
S._scripting = scripting;
opts = { baseURL: testBaseURL, System: S };
Expand Down
6 changes: 4 additions & 2 deletions lively.classes/tests/source-descriptor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ let S;
describe('source descriptors', function () {
beforeEach(async () => {
S = getSystem('test', { baseURL: testDir });
S.set('lively.transpiler.babel', System.get('lively.transpiler.babel'));
S.config({ transpiler: 'lively.transpiler.babel' });
const transpiler = System.transpiler;
S.set(transpiler, System.get(transpiler));
S.config({ transpiler });
S._loader.transpilerPromise = System._loader.transpilerPromise;
S.translate = async (load, opts) => await System.translate.bind(S)(load, opts);
S._scripting = System._scripting;
await createFiles(testDir, testResources);
Expand Down
7 changes: 4 additions & 3 deletions lively.freezer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
"build-landing-page": "./tools/build-landing-page.sh",
"build-unified": "./tools/build-unified.sh",
"build": "./tools/build-unified.sh",
"build-swc-plugin": "cd swc-plugin && cargo build --release --target wasm32-wasip1 && cp target/wasm32-wasip1/release/lively_swc_plugin.wasm lively_swc_plugin.wasm",
"build-swc-plugin-dev": "cd swc-plugin && cargo build --target wasm32-wasip1 && cp target/wasm32-wasip1/debug/lively_swc_plugin.wasm lively_swc_plugin.wasm",
"build-swc-plugin": "cd swc-plugin && cargo build --release --target wasm32-wasip1 -p lively-swc-plugin && cp target/wasm32-wasip1/release/lively_swc_plugin.wasm lively_swc_plugin.wasm",
"build-swc-plugin-dev": "cd swc-plugin && cargo build --target wasm32-wasip1 -p lively-swc-plugin && cp target/wasm32-wasip1/debug/lively_swc_plugin.wasm lively_swc_plugin.wasm",
"build-swc-browser": "cd swc-plugin && cargo build --release --target wasm32-unknown-unknown -p lively-swc-browser && wasm-bindgen --target web --out-dir ../swc-browser-wasm target/wasm32-unknown-unknown/release/lively_swc_browser.wasm",
"example-swc-bundler": "./tools/run-swc-example.sh",
"test-swc-plugin": "cd swc-plugin && cargo test"
"test-swc-plugin": "cd swc-plugin && cargo test -p lively-swc-transforms"
},
"systemjs": {
"map": {
Expand Down
24 changes: 19 additions & 5 deletions lively.freezer/src/bundler-swc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import path from 'path';
import { fileURLToPath } from 'url';
import { createHash } from 'crypto';

function hasInitializeClassRuntimeImport (code) {
return /^\s*import\s*\{\s*initializeClass\s+as\s+initializeES6ClassForLively\s*\}\s*from\s*['"](?:livelyClassesRuntime\.js|lively\.classes\/runtime\.js)['"]\s*;?/m.test(code);
}

/**
* SWC-based transform pipeline for lively.next
*/
Expand All @@ -19,7 +23,8 @@ export class LivelySwcTransform {
this.options = {
captureObj: '__varRecorder__',
exclude: [
'console', 'window', 'document', 'global', 'process', 'Buffer',
'console', 'window', 'document', 'global', 'globalThis', 'self', 'lively',
'process', 'Buffer',
'System', '__contextModule__',
'Object', 'Array', 'Function', 'String', 'Number', 'Boolean',
'Symbol', 'Date', 'Math', 'JSON', 'Promise', 'RegExp', 'Error',
Expand Down Expand Up @@ -54,7 +59,8 @@ export class LivelySwcTransform {
captureImports = true,
sourceMap = true,
filename = 'unknown.js',
moduleHash = null
moduleHash = null,
exclude = []
} = options;

const swcConfig = {
Expand All @@ -81,16 +87,24 @@ export class LivelySwcTransform {
};

const classToFunctionConfig = classToFunction || null;
const transformExclude = [...new Set([
...(this.options.exclude || []),
...(exclude || [])
])];

const livelyConfig = {
captureObj: this.options.captureObj,
declarationWrapper,
classToFunction: classToFunctionConfig,
exclude: this.options.exclude,
exclude: transformExclude,
captureImports,
rewriteMixedDefaultImports: false,
resurrection,
moduleId,
currentModuleAccessor: currentModuleAccessor || classToFunctionConfig?.currentModuleAccessor || null,
// Scope capture in bundle mode always uses FreezerRuntime.recorderFor().
// The class transform has its own currentModuleAccessor via classToFunction.currentModuleAccessor.
// Setting this to null ensures the FreezerRuntime path is used (not System.get("@lively-env").moduleEnv()).
currentModuleAccessor: null,
packageName,
packageVersion,
enableComponentTransform: true,
Expand All @@ -105,7 +119,7 @@ export class LivelySwcTransform {
const classRuntimeModule = resurrection ? 'livelyClassesRuntime.js' : 'lively.classes/runtime.js';
const classRuntimeImport = `import { initializeClass as initializeES6ClassForLively } from "${classRuntimeModule}";\n`;
const sourceForTransform = classToFunctionConfig &&
!code.includes('initializeClass as initializeES6ClassForLively')
!hasInitializeClassRuntimeImport(code)
? classRuntimeImport + code
: code;

Expand Down
13 changes: 8 additions & 5 deletions lively.freezer/src/util/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { updateBundledModules } from 'lively.modules/src/module.js';
import { Project } from 'lively.project/project.js';
import { pathForBrowserHistory } from 'lively.morphic/helpers.js';
import { installLinter } from 'lively.ide/js/linter.js';
import { setupBabelTranspiler } from 'lively.source-transform/babel/plugin.js';
import { setupSwcTranspiler } from 'lively.source-transform/swc/transpiler-setup.js';
import untar from 'js-untar';
import bowser from 'bowser';

Expand Down Expand Up @@ -185,8 +185,10 @@ async function shallowReloadModulesIfNeeded (modulesToCheck, moduleHashes, R) {
let key = modId;
let currMod;
if (key === '@empty') continue;
if (key.startsWith('esm://')) continue; // do not revive esm modules
if (modHash !== moduleHashes['/' + key]) {
if (key.startsWith('esm://') || key.startsWith('http://') || key.startsWith('https://')) continue; // do not revive CDN modules
const serverHash = moduleHashes['/' + key];
if (serverHash == null) continue; // module is not part of the server hash map
if (modHash !== serverHash) {
console.log('reviving', modId);
currMod = lively.modules.module(modId);
try {
Expand Down Expand Up @@ -233,7 +235,7 @@ function bootstrapLivelySystem (progress, fastLoad = query.fastLoad !== false ||
$world.env.installSystemChangeHandlers();

installLinter(System);
setupBabelTranspiler(System);
await setupSwcTranspiler(System);
logInfo('Setup SystemJS:', Date.now() - ts + 'ms');

// load packages
Expand Down Expand Up @@ -364,7 +366,8 @@ function bootstrapLivelySystem (progress, fastLoad = query.fastLoad !== false ||
const keysAfter = obj.keys(R.registry);
if (keysBefore.length < keysAfter.length) {
// detect modules to be reloaded
const modulesToUpdate = arr.withoutAll(keysAfter, keysBefore).filter(id => !id.startsWith('esm://'));
const modulesToUpdate = arr.withoutAll(keysAfter, keysBefore)
.filter(id => !id.startsWith('esm://') && !id.startsWith('http://') && !id.startsWith('https://'));
for (const mod of modulesToUpdate) {
System.set(System.decanonicalize(mod), System.newModule(R.exportsOf(mod)));
const m = lively.modules.module(mod);
Expand Down
23 changes: 20 additions & 3 deletions lively.freezer/src/util/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ export function runtimeDefinition () {
return globalValue;
}

function findRecorderExport (rec, ...names) {
for (let name of names) {
if (!name) continue;
if (name in rec) return { found: true, value: rec[name] };
// The SWC freezer transform materializes imported exports under an
// internal alias so SystemJS emits them; __module_exports__ keeps the
// public name.
const exportName = `__export_${name}__`;
if (exportName in rec) return { found: true, value: rec[exportName] };
}
return { found: false };
}

if (G.lively.FreezerRuntime) {
let [myMajor, myMinor, myPatch] = version.split('.').map(Number);
let [otherMajor, otherMinor, otherPatch] = G.lively.FreezerRuntime.version.split('.').map(Number);
Expand Down Expand Up @@ -587,13 +600,17 @@ export function runtimeDefinition () {
for (let exp of rec.__module_exports__) {
if (exp.startsWith('__rename__')) {
const [local, exported] = exp.replace('__rename__', '').split('->');
exports[exported] = rec[local];
const value = findRecorderExport(rec, local, exported);
if (value.found) exports[exported] = value.value;
} else if (exp.startsWith('__reexport__')) Object.assign(exports, this.exportsOf(exp.replace('__reexport__', '')));
else if (exp.startsWith('__default__')) {
const localName = exp.replace('__default__', '');
if (localName in rec) exports.default = rec[localName];
const value = findRecorderExport(rec, localName);
if (value.found) exports.default = value.value;
} else {
const value = findRecorderExport(rec, exp);
if (value.found) exports[exp] = value.value;
}
else if (exp in rec) exports[exp] = rec[exp];
}
return exports;
},
Expand Down
56 changes: 56 additions & 0 deletions lively.freezer/swc-browser-wasm/lively_swc_browser.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* tslint:disable */
/* eslint-disable */

/**
* Transform JavaScript source code using lively.next's SWC transforms,
* then wrap in System.register() format for SystemJS module loading.
*
* # Arguments
* * `source` - The JavaScript source code to transform
* * `config_json` - JSON string matching `LivelyTransformConfig`
*
* # Returns
* JSON string: `{ "code": "...", "map": "..." }`
*/
export function transform(source: string, config_json: string): string;

/**
* Returns the version of the transforms library.
*/
export function version(): string;

export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;

export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly transform: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly version: () => [number, number];
readonly __wbindgen_externrefs: WebAssembly.Table;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __externref_table_dealloc: (a: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_start: () => void;
}

export type SyncInitInput = BufferSource | WebAssembly.Module;

/**
* Instantiates the given `module`, which can either be bytes or
* a precompiled `WebAssembly.Module`.
*
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
*
* @returns {InitOutput}
*/
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;

/**
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
* for everything else, calls `WebAssembly.instantiate` directly.
*
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
*
* @returns {Promise<InitOutput>}
*/
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
Loading
Loading