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
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