Merge pull request #2 from emdash-cms/fix/virtual-module-optimizedeps
fix: exclude virtual:emdash from optimizeDeps to fix npm installs on Cloudflare
This commit is contained in:
5
.changeset/fix-virtual-module-optimizedeps.md
Normal file
5
.changeset/fix-virtual-module-optimizedeps.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"emdash": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix virtual module resolution errors when emdash is installed from npm on Cloudflare. The esbuild dependency pre-bundler was encountering `virtual:emdash/*` imports while crawling dist files and failing to resolve them. These are now excluded from the optimizeDeps scan.
|
||||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm build
|
- run: pnpm build
|
||||||
- run: pnpm typecheck
|
- run: pnpm typecheck
|
||||||
- run: pnpm run --filteremdash-demo --filter @emdash-cms/demo-cloudflare typecheck
|
- run: pnpm run --filter emdash-demo --filter @emdash-cms/demo-cloudflare typecheck
|
||||||
- run: pnpm typecheck:templates
|
- run: pnpm typecheck:templates
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@@ -138,7 +138,7 @@ jobs:
|
|||||||
cache: pnpm
|
cache: pnpm
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm build
|
- run: pnpm build
|
||||||
- run: pnpm --filteremdash exec vitest run --config vitest.smoke.config.ts
|
- run: pnpm --filter emdash exec vitest run --config vitest.smoke.config.ts
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
env:
|
env:
|
||||||
DATABASE_URL: postgres://postgres:test@localhost:5432/emdash_smoke
|
DATABASE_URL: postgres://postgres:test@localhost:5432/emdash_smoke
|
||||||
|
|||||||
@@ -269,6 +269,13 @@ export function createViteConfig(
|
|||||||
// Vite discovers them one-by-one on first request, causing workerd
|
// Vite discovers them one-by-one on first request, causing workerd
|
||||||
// to enter "worker cancelled" state on cold cache.
|
// to enter "worker cancelled" state on cold cache.
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
|
// Exclude EmDash virtual modules from esbuild's dependency
|
||||||
|
// scan. These are resolved by the Vite plugin at transform time,
|
||||||
|
// but esbuild encounters them when crawling emdash's dist files
|
||||||
|
// during pre-bundling and can't resolve them. Vite's exclude
|
||||||
|
// uses prefix matching (id.startsWith(m + "/")), so
|
||||||
|
// "virtual:emdash" matches all "virtual:emdash/*" imports.
|
||||||
|
exclude: ["virtual:emdash"],
|
||||||
include: [
|
include: [
|
||||||
// EmDash direct deps
|
// EmDash direct deps
|
||||||
"emdash > @portabletext/toolkit",
|
"emdash > @portabletext/toolkit",
|
||||||
@@ -322,7 +329,7 @@ export function createViteConfig(
|
|||||||
include: useSource
|
include: useSource
|
||||||
? ["@astrojs/react/client.js"]
|
? ["@astrojs/react/client.js"]
|
||||||
: ["@emdash-cms/admin", "@astrojs/react/client.js"],
|
: ["@emdash-cms/admin", "@astrojs/react/client.js"],
|
||||||
exclude: cloudflare ? [] : NODE_NATIVE_EXTERNALS,
|
exclude: cloudflare ? ["virtual:emdash"] : [...NODE_NATIVE_EXTERNALS, "virtual:emdash"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
// References entries in ec_* tables by collection + entry_id
|
// References entries in ec_* tables by collection + entry_id
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("revisions")
|
.createTable("revisions")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("id", "text", (col) => col.primaryKey())
|
.addColumn("id", "text", (col) => col.primaryKey())
|
||||||
.addColumn("collection", "text", (col) => col.notNull()) // e.g., 'posts'
|
.addColumn("collection", "text", (col) => col.notNull()) // e.g., 'posts'
|
||||||
.addColumn("entry_id", "text", (col) => col.notNull()) // ID in the ec_* table
|
.addColumn("entry_id", "text", (col) => col.notNull()) // ID in the ec_* table
|
||||||
@@ -24,6 +25,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
|
|
||||||
await db.schema
|
await db.schema
|
||||||
.createIndex("idx_revisions_entry")
|
.createIndex("idx_revisions_entry")
|
||||||
|
.ifNotExists()
|
||||||
.on("revisions")
|
.on("revisions")
|
||||||
.columns(["collection", "entry_id"])
|
.columns(["collection", "entry_id"])
|
||||||
.execute();
|
.execute();
|
||||||
@@ -31,6 +33,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
// Taxonomies
|
// Taxonomies
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("taxonomies")
|
.createTable("taxonomies")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("id", "text", (col) => col.primaryKey())
|
.addColumn("id", "text", (col) => col.primaryKey())
|
||||||
.addColumn("name", "text", (col) => col.notNull())
|
.addColumn("name", "text", (col) => col.notNull())
|
||||||
.addColumn("slug", "text", (col) => col.notNull())
|
.addColumn("slug", "text", (col) => col.notNull())
|
||||||
@@ -43,11 +46,17 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
)
|
)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
await db.schema.createIndex("idx_taxonomies_name").on("taxonomies").column("name").execute();
|
await db.schema
|
||||||
|
.createIndex("idx_taxonomies_name")
|
||||||
|
.ifNotExists()
|
||||||
|
.on("taxonomies")
|
||||||
|
.column("name")
|
||||||
|
.execute();
|
||||||
|
|
||||||
// Content-Taxonomy junction - references entries in ec_* tables
|
// Content-Taxonomy junction - references entries in ec_* tables
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("content_taxonomies")
|
.createTable("content_taxonomies")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("collection", "text", (col) => col.notNull()) // e.g., 'posts'
|
.addColumn("collection", "text", (col) => col.notNull()) // e.g., 'posts'
|
||||||
.addColumn("entry_id", "text", (col) => col.notNull()) // ID in the ec_* table
|
.addColumn("entry_id", "text", (col) => col.notNull()) // ID in the ec_* table
|
||||||
.addColumn("taxonomy_id", "text", (col) => col.notNull())
|
.addColumn("taxonomy_id", "text", (col) => col.notNull())
|
||||||
@@ -64,6 +73,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
// Media
|
// Media
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("media")
|
.createTable("media")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("id", "text", (col) => col.primaryKey())
|
.addColumn("id", "text", (col) => col.primaryKey())
|
||||||
.addColumn("filename", "text", (col) => col.notNull())
|
.addColumn("filename", "text", (col) => col.notNull())
|
||||||
.addColumn("mime_type", "text", (col) => col.notNull())
|
.addColumn("mime_type", "text", (col) => col.notNull())
|
||||||
@@ -80,6 +90,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
|
|
||||||
await db.schema
|
await db.schema
|
||||||
.createIndex("idx_media_content_hash")
|
.createIndex("idx_media_content_hash")
|
||||||
|
.ifNotExists()
|
||||||
.on("media")
|
.on("media")
|
||||||
.column("content_hash")
|
.column("content_hash")
|
||||||
.execute();
|
.execute();
|
||||||
@@ -87,6 +98,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
// Users
|
// Users
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("users")
|
.createTable("users")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("id", "text", (col) => col.primaryKey())
|
.addColumn("id", "text", (col) => col.primaryKey())
|
||||||
.addColumn("email", "text", (col) => col.notNull().unique())
|
.addColumn("email", "text", (col) => col.notNull().unique())
|
||||||
.addColumn("password_hash", "text", (col) => col.notNull())
|
.addColumn("password_hash", "text", (col) => col.notNull())
|
||||||
@@ -97,11 +109,17 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
await db.schema.createIndex("idx_users_email").on("users").column("email").execute();
|
await db.schema
|
||||||
|
.createIndex("idx_users_email")
|
||||||
|
.ifNotExists()
|
||||||
|
.on("users")
|
||||||
|
.column("email")
|
||||||
|
.execute();
|
||||||
|
|
||||||
// Options (key-value store)
|
// Options (key-value store)
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("options")
|
.createTable("options")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("name", "text", (col) => col.primaryKey())
|
.addColumn("name", "text", (col) => col.primaryKey())
|
||||||
.addColumn("value", "text", (col) => col.notNull())
|
.addColumn("value", "text", (col) => col.notNull())
|
||||||
.execute();
|
.execute();
|
||||||
@@ -109,6 +127,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
// Audit logs (security events)
|
// Audit logs (security events)
|
||||||
await db.schema
|
await db.schema
|
||||||
.createTable("audit_logs")
|
.createTable("audit_logs")
|
||||||
|
.ifNotExists()
|
||||||
.addColumn("id", "text", (col) => col.primaryKey())
|
.addColumn("id", "text", (col) => col.primaryKey())
|
||||||
.addColumn("timestamp", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
.addColumn("timestamp", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
||||||
.addColumn("actor_id", "text")
|
.addColumn("actor_id", "text")
|
||||||
@@ -120,9 +139,24 @@ export async function up(db: Kysely<unknown>): Promise<void> {
|
|||||||
.addColumn("status", "text")
|
.addColumn("status", "text")
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
await db.schema.createIndex("idx_audit_actor").on("audit_logs").column("actor_id").execute();
|
await db.schema
|
||||||
await db.schema.createIndex("idx_audit_action").on("audit_logs").column("action").execute();
|
.createIndex("idx_audit_actor")
|
||||||
await db.schema.createIndex("idx_audit_timestamp").on("audit_logs").column("timestamp").execute();
|
.ifNotExists()
|
||||||
|
.on("audit_logs")
|
||||||
|
.column("actor_id")
|
||||||
|
.execute();
|
||||||
|
await db.schema
|
||||||
|
.createIndex("idx_audit_action")
|
||||||
|
.ifNotExists()
|
||||||
|
.on("audit_logs")
|
||||||
|
.column("action")
|
||||||
|
.execute();
|
||||||
|
await db.schema
|
||||||
|
.createIndex("idx_audit_timestamp")
|
||||||
|
.ifNotExists()
|
||||||
|
.on("audit_logs")
|
||||||
|
.column("timestamp")
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(db: Kysely<unknown>): Promise<void> {
|
export async function down(db: Kysely<unknown>): Promise<void> {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
{
|
{
|
||||||
"binding": "DB",
|
"binding": "DB",
|
||||||
"database_name": "my-emdash-site",
|
"database_name": "my-emdash-site",
|
||||||
// Run `wrangler d1 create my-emdash-site` and paste the ID here
|
// Run `wrangler d1 create my-emdash-site` and paste the real ID here for deploy
|
||||||
"database_id": "",
|
"database_id": "local",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
{
|
{
|
||||||
"binding": "DB",
|
"binding": "DB",
|
||||||
"database_name": "my-marketing-site",
|
"database_name": "my-marketing-site",
|
||||||
// Run `wrangler d1 create my-marketing-site` and paste the ID here
|
// Run `wrangler d1 create my-marketing-site` and paste the real ID here for deploy
|
||||||
"database_id": "",
|
"database_id": "local",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
{
|
{
|
||||||
"binding": "DB",
|
"binding": "DB",
|
||||||
"database_name": "my-portfolio-site",
|
"database_name": "my-portfolio-site",
|
||||||
// Run `wrangler d1 create my-portfolio-site` and paste the ID here
|
// Run `wrangler d1 create my-portfolio-site` and paste the real ID here for deploy
|
||||||
"database_id": "",
|
"database_id": "local",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
|
|||||||
6
templates/starter-cloudflare/emdash-env.d.ts
vendored
6
templates/starter-cloudflare/emdash-env.d.ts
vendored
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
/// <reference types="emdash/locals" />
|
/// <reference types="emdash/locals" />
|
||||||
|
|
||||||
import type { PortableTextBlock } from "emdash";
|
import type { ContentBylineCredit, PortableTextBlock } from "emdash";
|
||||||
|
|
||||||
export interface Page {
|
export interface Page {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -14,6 +14,7 @@ export interface Page {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
publishedAt: Date | null;
|
publishedAt: Date | null;
|
||||||
|
bylines?: ContentBylineCredit[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Post {
|
export interface Post {
|
||||||
@@ -27,6 +28,7 @@ export interface Post {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
publishedAt: Date | null;
|
publishedAt: Date | null;
|
||||||
|
bylines?: ContentBylineCredit[];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "emdash" {
|
declare module "emdash" {
|
||||||
@@ -34,4 +36,4 @@ declare module "emdash" {
|
|||||||
pages: Page;
|
pages: Page;
|
||||||
posts: Post;
|
posts: Post;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
{
|
{
|
||||||
"binding": "DB",
|
"binding": "DB",
|
||||||
"database_name": "my-emdash-site",
|
"database_name": "my-emdash-site",
|
||||||
// Run `wrangler d1 create my-emdash-site` and paste the ID here
|
// Run `wrangler d1 create my-emdash-site` and paste the real ID here for deploy
|
||||||
"database_id": "",
|
"database_id": "local",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
|
|||||||
Reference in New Issue
Block a user