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
34 changes: 34 additions & 0 deletions src/build/tish.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,39 @@ export async function compileEsm(root, entry, outDir, extra = []) {
const { out } = await tish(root, ['build', entry, '-o', outDir, '--target', 'js', '--format', 'esm', '--jsx-import-source', '@tishlang/orbit', ...extra])
const m = /Entry:\s*(.+)/.exec(out)
if (!m) throw new Error('tish build did not report an entry file:\n' + out)
markEsm(outDir)
return path.resolve(root, m[1].trim())
}

// The compiled packages under <outDir>/node_modules (@tishlang/orbit, …) are ES modules, but tish
// writes them without a package.json. Node never looks past a node_modules folder for one, so it
// takes them for CommonJS, and stricter loaders (Vercel's Node runtime) then fail on their named
// exports ("Named export 'Fragment' not found"). Give each package folder {"type": "module"}.
function markEsm(outDir) {
const mark = dir => {
const pj = path.join(dir, 'package.json')
if (!fs.existsSync(pj)) fs.writeFileSync(pj, JSON.stringify({ type: 'module' }) + '\n')
}
const isDir = p => fs.statSync(p).isDirectory()
const walk = dir => {
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name)
if (!isDir(p)) continue
if (name === 'node_modules') {
for (const pkg of fs.readdirSync(p)) {
const pp = path.join(p, pkg)
if (!isDir(pp)) continue
if (pkg.startsWith('@')) {
for (const sub of fs.readdirSync(pp)) if (isDir(path.join(pp, sub))) { mark(path.join(pp, sub)); walk(path.join(pp, sub)) }
} else {
mark(pp)
walk(pp)
}
}
} else {
walk(p)
}
}
}
walk(outDir)
}
4 changes: 4 additions & 0 deletions test/e2e.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ console.log('trailingSlash: true (default)')
check(cfg.version === 3, 'vercel config v3', cfg.version)
check(cfg.routes.some(x => x.status === 308 && x.headers?.Location === '/$1/'), 'vercel adds the trailing slash', null)
check(fs.existsSync(path.join(dir, '.vercel', 'output', 'functions', '_orbit.func', 'index.mjs')), 'vercel server function', null)
const unmarked = []
const scan = d => { for (const n of fs.readdirSync(d)) { const p = path.join(d, n); if (!fs.statSync(p).isDirectory()) continue; if (path.basename(d) === 'node_modules' || path.basename(path.dirname(d)) === 'node_modules' && path.basename(d).startsWith('@')) { if (!n.startsWith('@') && !fs.existsSync(path.join(p, 'package.json'))) unmarked.push(p) } scan(p) } }
scan(path.join(dir, '.vercel', 'output', 'functions', '_orbit.func', 'server'))
check(unmarked.length === 0, 'compiled packages are marked as ES modules', unmarked)
check(fs.existsSync(path.join(dir, '.vercel', 'output', 'static', 'index.html')), 'vercel static pages', null)
// The function Vercel runs, behind a plain Node server.
const fn = (await import(path.join(dir, '.vercel', 'output', 'functions', '_orbit.func', 'index.mjs'))).default
Expand Down
Loading