Skip to content

Commit

Permalink
Merge 151be67 into 0aa3bd8
Browse files Browse the repository at this point in the history
  • Loading branch information
Fryuni authored Feb 7, 2024
2 parents 0aa3bd8 + 151be67 commit 6aa9225
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 329 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-shrimps-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inox-tools/inline-mod": minor
---

Add support for serializing URL objects
5 changes: 5 additions & 0 deletions .changeset/fresh-beers-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inox-tools/inline-mod": minor
---

Implement support for async magic factory
5 changes: 5 additions & 0 deletions .changeset/itchy-pants-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inox-tools/inline-mod": patch
---

Handle import errors on cache build
22 changes: 22 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"mode": "pre",
"tag": "smart-factory",
"initialVersions": {
"docs": "0.0.1",
"@examples/custom-routing": "0.0.1",
"@example/inline-mod": "0.0.0",
"inline-mod-astro": "0.0.1",
"@inox-tools/custom-routing": "0.2.0",
"@inox-tools/inline-mod": "1.0.1",
"@inox-tools/velox-luna": "0.0.1",
"turbo": "1.0.0",
"templates": "1.0.0"
},
"changesets": [
"eleven-shrimps-rest",
"fresh-beers-dream",
"itchy-pants-happen",
"tame-rivers-tie",
"thick-plums-prove"
]
}
5 changes: 5 additions & 0 deletions .changeset/tame-rivers-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inox-tools/inline-mod": patch
---

Fix dependency import path search
5 changes: 5 additions & 0 deletions .changeset/thick-plums-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inox-tools/inline-mod": minor
---

Add new factory utility
11 changes: 9 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ on:
push:
branches:
- main
pull_request:
types:
- opened
- reopened
- synchronize
- labeled

defaults:
run:
Expand All @@ -18,6 +24,7 @@ jobs:
changelog:
name: Changelog PR or Release
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'preview') }}
permissions:
contents: write
id-token: write
Expand Down Expand Up @@ -46,8 +53,8 @@ jobs:
# Note: pnpm install after versioning is necessary to refresh lockfile
version: pnpm run version
publish: pnpm exec changeset publish
commit: "[ci] release"
title: "[ci] release"
commit: ${{ github.event_name == 'push' && '[ci] release' || '[pre] release' }}
title: ${{ github.event_name == 'push' && '[ci] release' || '[pre] release' }}
env:
# Needs access to push to main
GITHUB_TOKEN: ${{ secrets.COMMIT_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"lint": "eslint . --report-unused-disable-directives --fix",
"release": "pnpm run build && changeset publish",
"test": "turbo run test --concurrency=1",
"version": "changeset version"
"version": "changeset version && pnpm install && pnpm format"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
Expand Down
18 changes: 18 additions & 0 deletions packages/inline-mod/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# @inox-tools/inline-mod

## 1.1.0-smart-factory.3

### Minor Changes

- d430acc: Add support for serializing URL objects

### Patch Changes

- 645a2e4: Handle import errors on cache build
- 2e7a6af: Fix dependency import path search

## 1.1.0-smart-factory.0

### Minor Changes

- 8aca13a: Implement support for async magic factory
- db4e594: Add new factory utility

## 1.0.1

### Patch Changes
Expand Down
8 changes: 4 additions & 4 deletions packages/inline-mod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@inox-tools/inline-mod",
"version": "1.0.1",
"version": "1.1.0-smart-factory.3",
"description": "Define a virtual module inline with any reference to buildtime values",
"keywords": [
"vite-plugin"
Expand All @@ -10,15 +10,15 @@
"author": "Luiz Ferraz <luiz@lferraz.com>",
"type": "module",
"exports": {
".": "./dist/index.js",
"./vite": {
"types": "./dist/vite.d.ts",
"default": "./dist/vite.js"
}
},
"files": [
"README.md",
"src"
"src",
"dist"
],
"scripts": {
"build": "tsup",
Expand All @@ -42,7 +42,7 @@
"vitest": "^1.2.2"
},
"peerDependencies": {
"vite": "^3.2.0"
"vite": "^4 || ^5"
},
"peerDependenciesMeta": {
"vite": {
Expand Down
17 changes: 14 additions & 3 deletions packages/inline-mod/src/closure/entry.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isDeepStrictEqual } from 'util';
import type { InspectedFunction, InspectedObject } from './types.js';

type EntryMap = {
Expand All @@ -10,6 +11,11 @@ type EntryMap = {
// A closure we are dependent on.
function: InspectedFunction;

factory: {
isAsync: boolean;
factory: Entry<'function'>;
};

// An object which may contain nested closures.
// Can include an optional proto if the user is not using the default Object.prototype.
object: InspectedObject;
Expand Down Expand Up @@ -40,12 +46,17 @@ type EntryMap = {
// A simple expression to use to represent this instance. For example "global.Number";
expr: string;

// A simple expression to use to construct an instance. The reference of the instance is relevant.
refExpr: string;

// A placeholder for a pending entry
pending: never;
};

export type Entry<T extends keyof EntryMap = keyof EntryMap> = {
[K in keyof EntryMap]: {
export type EntryType = keyof EntryMap;

export type Entry<T extends EntryType = EntryType> = {
[K in EntryType]: {
type: K;
value: EntryMap[K];
};
Expand Down Expand Up @@ -105,7 +116,7 @@ export class EntryRegistry<K> {
const existingEntry = this.lookup(key);

if (existingEntry !== undefined) {
if (Object.is(existingEntry, entry)) {
if (Object.is(existingEntry, entry) || isDeepStrictEqual(existingEntry, entry)) {
// Entry already stored. Do nothing.
return existingEntry;
}
Expand Down
136 changes: 121 additions & 15 deletions packages/inline-mod/src/closure/inspectCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,9 @@ class Inspector {

log('Error during inspection:', error);

throw new InternalInspectionError(
error instanceof Error ? error.message : `${error}`,
this.frames,
error.stack
);
if (!(error instanceof Error)) throw error;

throw new InternalInspectionError(error.message, this.frames, error.stack);
}
}

Expand Down Expand Up @@ -275,6 +273,17 @@ class Inspector {
value: object,
capturedProperties?: CapturedPropertyChain[]
): Promise<Entry> {
const factoryInfo = tryExtractMagicFactory(value);
if (factoryInfo) {
return {
type: 'factory',
value: {
isAsync: factoryInfo.isAsync,
factory: (await this.inspect(factoryInfo.factory)) as Entry<'function'>,
},
};
}

if (this.doNotCapture(value)) {
log('Value should skip capture');
return Entry.json();
Expand All @@ -301,6 +310,13 @@ class Inspector {
};
}

if (value instanceof URL) {
return {
type: 'refExpr',
value: `new URL(${JSON.stringify(value.toString())})`,
};
}

if (Array.isArray(value)) {
log('Inspecting array value');
const array: Entry[] = [];
Expand Down Expand Up @@ -843,10 +859,11 @@ const bannedBuiltInModules = new Set<string>([

// References to WASI module can't be serialized at the moment.
'wasi',
'tty',
]);

const moduleLookup = Lazy.of(async () => {
const _log = log.extend('builtInLoader');
const _log = getLogger('builtInLoader');

const reverseModuleCache = new Map<unknown, Entry<'module' | 'moduleValue'>>();

Expand Down Expand Up @@ -942,16 +959,22 @@ async function findModuleEntry(obj: any): Promise<Entry<'module' | 'moduleValue'
// node_modules that we actually upload with our serialized functions.
const modReference = getModuleFromPath(modPath);

const rawImport = await import(mod.id);
try {
// const rawImport = await import(/* @vite-ignore */ mod.id);
const rawImport = mod.exports;

if (!reverseModuleCache.has(rawImport)) {
reverseModuleCache.set(rawImport, {
type: 'module',
value: {
type: 'star',
reference: modReference,
},
});
if (!reverseModuleCache.has(rawImport)) {
reverseModuleCache.set(rawImport, {
type: 'module',
value: {
type: 'star',
reference: modReference,
},
});
}
} catch (err) {
log('Failed on:', mod, err);
throw err;
}

if (mod.exports.default !== undefined && !reverseModuleCache.has(mod.exports.default)) {
Expand Down Expand Up @@ -995,6 +1018,89 @@ function isDerivedNoCaptureConstructor(func: Function): boolean {
return false;
}

const factorySymbol = Symbol('inox-tool/inline-factory');

type MagicPlaceholder = {
[factorySymbol]: {
initialized: boolean;
isAsync: boolean;
factory: () => Record<any, any>;
};
};

function ensureFactoryInitialized(magicValue: MagicPlaceholder): void {
if (!magicValue[factorySymbol].initialized) {
Object.assign(magicValue, magicValue[factorySymbol].factory());
magicValue[factorySymbol].initialized = true;
}
}

const magicFactoryProxyHandler: ProxyHandler<MagicPlaceholder> = {
has: (target, key) => {
if (key === factorySymbol) return true;
ensureFactoryInitialized(target);

return Reflect.has(target, key);
},
get: (target, key) => {
if (key === factorySymbol) {
return {
isAsync: target[factorySymbol].isAsync,
factory: target[factorySymbol].factory,
};
}

ensureFactoryInitialized(target);

return Reflect.get(target, key);
},
set: (target, key, value) => {
if (key === factorySymbol) {
return false;
}

ensureFactoryInitialized(target);

return Reflect.set(target, key, value);
},
ownKeys: (target) => {
ensureFactoryInitialized(target);

return Reflect.ownKeys(target).filter((k) => k !== factorySymbol);
},
};

export function magicFactory<T extends Record<any, any>>({
isAsync,
fn,
}: {
isAsync: boolean;
fn: T | (() => T);
}): T {
if (typeof fn !== 'function') {
return fn;
}

return new Proxy<T & MagicPlaceholder>(
{
// Trick for TS
...({} as T),
[factorySymbol]: {
initialized: false,
isAsync,
factory: fn,
},
},
magicFactoryProxyHandler
);
}

function tryExtractMagicFactory(value: any): MagicPlaceholder[typeof factorySymbol] | undefined {
if (factorySymbol in value) {
return value[factorySymbol];
}
}

/**
* Cache of global entries
*/
Expand Down
Loading

0 comments on commit 6aa9225

Please sign in to comment.