Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions .changeset/deno-production-builds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@builder.io/qwik': patch
'@builder.io/qwik-city': patch
---

FIX: support Deno as package manager for production builds. The Vite plugin now recognizes Deno as a Node-compatible runtime for manifest passing, and SSG delegates to the Node implementation instead of stubbing out.
8 changes: 0 additions & 8 deletions packages/qwik-city/src/static/deno/index.ts

This file was deleted.

5 changes: 1 addition & 4 deletions packages/qwik-city/src/static/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ export async function generate(opts: StaticGenerateOptions) {
export type { StaticGenerateOptions, StaticGenerateRenderOptions, StaticGenerateResult };

function getEntryModulePath() {
if (isDeno()) {
return './deno.mjs';
}
if (isNode() || isBun()) {
if (isNode() || isBun() || isDeno()) {
if (isCjs()) {
return './node.cjs';
}
Expand Down
12 changes: 8 additions & 4 deletions packages/qwik/src/optimizer/src/plugins/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
OptimizerOptions,
OptimizerSystem,
QwikManifest,
SystemEnvironment,
TransformModule,
} from '../types';
import { type BundleGraphAdder } from './bundle-graph';
Expand Down Expand Up @@ -191,7 +192,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
pluginOpts.input = viteConfig.build?.lib.entry;
}
}
if (sys.env === 'node' || sys.env === 'bun') {
if (hasNodeCompat(sys.env)) {
const fs: typeof import('fs') = await sys.dynamicImport('node:fs');

try {
Expand Down Expand Up @@ -551,7 +552,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
);

const sys = qwikPlugin.getSys();
if (tmpClientManifestPath && (sys.env === 'node' || sys.env === 'bun')) {
if (tmpClientManifestPath && hasNodeCompat(sys.env)) {
// Client build should write the manifest to a tmp dir
const fs: typeof import('fs') = await sys.dynamicImport('node:fs');
await fs.promises.writeFile(tmpClientManifestPath, clientManifestStr);
Expand All @@ -566,7 +567,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
// ssr build

const sys = qwikPlugin.getSys();
if (sys.env === 'node' || sys.env === 'bun') {
if (hasNodeCompat(sys.env)) {
const outputs = Object.keys(rollupBundle);

// In order to simplify executing the server script with a common script
Expand Down Expand Up @@ -758,7 +759,7 @@ const findQwikRoots = async (
packageJsonDir: string
): Promise<QwikPackages[]> => {
const paths = new Map<string, string>();
if (sys.env === 'node' || sys.env === 'bun') {
if (hasNodeCompat(sys.env)) {
const fs: typeof import('fs') = await sys.dynamicImport('node:fs');
let prevPackageJsonDir: string | undefined;
do {
Expand Down Expand Up @@ -819,6 +820,9 @@ export const isNotNullable = <T>(v: T): v is NonNullable<T> => {
return v != null;
};

/** Whether the runtime supports Node standard library APIs (node:fs, node:os, etc.). */
const hasNodeCompat = (env: SystemEnvironment) => env === 'node' || env === 'bun' || env === 'deno';

const VITE_CLIENT_MODULE = `@builder.io/qwik/vite-client`;
const CLIENT_DEV_INPUT = 'entry.dev';

Expand Down
49 changes: 47 additions & 2 deletions packages/qwik/src/optimizer/src/plugins/vite.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ const chunkInfoMocks = [
},
] as Rollup.PreRenderedChunk[];

function mockOptimizerOptions(): OptimizerOptions {
function mockOptimizerOptions(env: 'node' | 'deno' = 'node'): OptimizerOptions {
return {
sys: {
cwd: () => process.cwd(),
env: 'node',
env,
os: process.platform,
dynamicImport: async (path) => import(path),
strictDynamicImport: async (path) => import(path),
Expand Down Expand Up @@ -417,6 +417,51 @@ test('should use build.outDir config when assetsDir is _astro', async () => {
assert.equal(c.build.outDir, normalizePath(resolve(cwd, `dist/`)));
});

test('command: build, mode: production (deno)', async () => {
const initOpts = {
optimizerOptions: mockOptimizerOptions('deno'),
};
const plugin = getPlugin(initOpts);
const c = (await plugin.config.call(
configHookPluginContext,
{},
{ command: 'build', mode: 'production' }
))!;
const opts = await plugin.api?.getOptions();

assert.deepEqual(opts.target, 'client');
assert.deepEqual(opts.buildMode, 'production');
assert.deepEqual(opts.resolveQwikBuild, true);

// Deno should produce the same config shape as Node
const build = c.build!;
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'dist')));
assert.deepEqual(build.dynamicImportVarsOptions?.exclude, [/./]);
assert.deepEqual(build.ssr, undefined);
});

test('command: build, --ssr entry.server.tsx (deno)', async () => {
const initOpts = {
optimizerOptions: mockOptimizerOptions('deno'),
};
const plugin = getPlugin(initOpts);
const c = (await plugin.config.call(
configHookPluginContext,
{ build: { ssr: resolve(cwd, 'src', 'entry.server.tsx') } },
{ command: 'build', mode: '' }
))!;
const opts = await plugin.api?.getOptions();

assert.deepEqual(opts.target, 'ssr');
assert.deepEqual(opts.buildMode, 'development');
assert.deepEqual(opts.entryStrategy, { type: 'hoist' });

const build = c.build!;
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'server')));
assert.deepEqual(build.ssr, true);
assert.deepEqual(c.publicDir, false);
});

test('command: build, --mode lib', async () => {
const initOpts = {
optimizerOptions: mockOptimizerOptions(),
Expand Down
14 changes: 0 additions & 14 deletions scripts/qwik-city.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export async function buildQwikCity(config: BuildConfig) {
buildMiddlewareFirebase(config),
buildStatic(config),
buildStaticNode(config),
buildStaticDeno(config),
]);

await buildRuntime(config);
Expand Down Expand Up @@ -637,19 +636,6 @@ async function buildStatic(config: BuildConfig) {
});
}

async function buildStaticDeno(config: BuildConfig) {
const entryPoints = [join(config.srcQwikCityDir, 'static', 'deno', 'index.ts')];

await build({
entryPoints,
outfile: join(config.distQwikCityPkgDir, 'static', 'deno.mjs'),
bundle: true,
platform: 'neutral',
format: 'esm',
plugins: [resolveRequestHandler('../middleware/request-handler/index.mjs')],
});
}

async function buildStaticNode(config: BuildConfig) {
const entryPoints = [join(config.srcQwikCityDir, 'static', 'node', 'index.ts')];

Expand Down