Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): throw when importing twice #7109

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"fixed": [["@builder.io/qwik", "@builder.io/qwik-city", "eslint-plugin-qwik", "create-qwik"]],
"linked": [],
"access": "public",
"baseBranch": "upcoming",
"baseBranch": "origin/upcoming",
"updateInternalDependencies": "minor",
"ignore": [
"qwik-docs",
Expand Down
20 changes: 0 additions & 20 deletions .changeset/good-jars-mix.md

This file was deleted.

5 changes: 5 additions & 0 deletions .changeset/lemon-dingos-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@builder.io/qwik': minor
---

BREAKING: (slightly) Qwik will no longer scan all modules at build start to detect Qwik modules. Instead, a runtime check is done to prevent duplicate core imports. If you get a runtime error, you need to fix your build settings so they don't externalize qwik-related libraries.
7 changes: 0 additions & 7 deletions .changeset/tiny-pants-scream.md

This file was deleted.

2 changes: 2 additions & 0 deletions packages/create-qwik/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# create-qwik

## 1.11.0

## 1.10.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/create-qwik/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "create-qwik",
"description": "Interactive CLI for create Qwik projects and adding features.",
"version": "1.10.0",
"version": "1.11.0",
"author": "Builder.io Team",
"bin": "./create-qwik.cjs",
"bugs": "https://github.com/QwikDev/qwik/issues",
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin-qwik/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# eslint-plugin-qwik

## 1.11.0

## 1.10.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-qwik/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "eslint-plugin-qwik",
"description": "An Open-Source sub-framework designed with a focus on server-side-rendering, lazy-loading, and styling/animation.",
"version": "1.10.0",
"version": "1.11.0",
"author": "Builder Team",
"bugs": "https://github.com/QwikDev/qwik/issues",
"dependencies": {
Expand Down
2 changes: 2 additions & 0 deletions packages/qwik-city/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @builder.io/qwik-city

## 1.11.0

## 1.10.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/qwik-city/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@builder.io/qwik-city",
"description": "The meta-framework for Qwik.",
"version": "1.10.0",
"version": "1.11.0",
"bugs": "https://github.com/QwikDev/qwik/issues",
"dependencies": {
"@mdx-js/mdx": "^3",
Expand Down
6 changes: 6 additions & 0 deletions packages/qwik-city/src/static/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { WritableStream } from 'node:stream/web';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';

export async function workerThread(sys: System) {
// Special case: we allow importing qwik again in the same process, it's ok because we just needed the serializer
// TODO: remove this once we have vite environment API and no longer need the serializer separately
delete (globalThis as any).__qwik;
const ssgOpts = sys.getOptions();
const pendingPromises = new Set<Promise<any>>();

Expand Down Expand Up @@ -40,6 +43,9 @@ export async function workerThread(sys: System) {
}

export async function createSingleThreadWorker(sys: System) {
// Special case: we allow importing qwik again in the same process, it's ok because we just needed the serializer
// TODO: remove this once we have vite environment API and no longer need the serializer separately
delete (globalThis as any).__qwik;
const ssgOpts = sys.getOptions();
const pendingPromises = new Set<Promise<any>>();

Expand Down
25 changes: 25 additions & 0 deletions packages/qwik/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# @builder.io/qwik

## 1.11.0

### Minor Changes

- CHORE: Prepare backwards compatibility for V1 libraries in V2. (by [@wmertens](https://github.com/wmertens) in [#7044](https://github.com/QwikDev/qwik/pull/7044))

We move internal fields `immutableProps` and `flags` out of JSXNode as they are not meant for public use.

This will allow projects using older V1 libraries to continue to work with the Qwik V2 by adding the following `package.json` changes:

```json
{
"dependencies": {
"@builder.io/qwik": "^1.11.0",
"@qwik.dev/core": "^2.0.0"
}
}
```

And will prevent typescript errors when using libraries which haven't upgraded to V2 yet.

- ✨ add monorepo support to the `qwik add` command by adding a `projectDir` param (by [@shairez](https://github.com/shairez) in [#7059](https://github.com/QwikDev/qwik/pull/7059))

That way you can run `qwik add --projectDir=packages/my-package` and it will add the feature to the specified project/package (sub) folder, instead of the root folder.

## 1.10.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/qwik/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@builder.io/qwik",
"description": "An Open-Source sub-framework designed with a focus on server-side-rendering, lazy-loading, and styling/animation.",
"version": "1.10.0",
"version": "1.11.0",
"annotation": "This package.json is for internal use in the monorepo, the build actually makes a new package.json for the published package via scripts/package-json.ts",
"bin": {
"qwik": "./qwik-cli.cjs"
Expand Down
11 changes: 11 additions & 0 deletions packages/qwik/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Protect against duplicate imports
//////////////////////////////////////////////////////////////////////////////////////////
import { version } from './version';
if ((globalThis as any).__qwik) {
throw new Error(
`Qwik version ${(globalThis as any).__qwik} already imported while importing ${version}. Verify external vs bundled imports etc.`
);
}
(globalThis as any).__qwik = version;

//////////////////////////////////////////////////////////////////////////////////////////
// Developer Core API
//////////////////////////////////////////////////////////////////////////////////////////
Expand Down
99 changes: 2 additions & 97 deletions packages/qwik/src/optimizer/src/plugins/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type {
InsightManifest,
Optimizer,
OptimizerOptions,
OptimizerSystem,
Path,
QwikBundleGraph,
QwikManifest,
Expand All @@ -31,7 +30,6 @@ import {
type NormalizedQwikPluginOptions,
type QwikBuildMode,
type QwikBuildTarget,
type QwikPackages,
type QwikPluginOptions,
} from './plugin';
import { createRollupError, normalizeRollupOutputOptions } from './rollup';
Expand Down Expand Up @@ -158,8 +156,6 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
}
}

const shouldFindVendors =
!qwikViteOpts.disableVendorScan && (target !== 'lib' || viteCommand === 'serve');
viteAssetsDir = viteConfig.build?.assetsDir;
const useAssetsDir = target === 'client' && !!viteAssetsDir && viteAssetsDir !== '_astro';
const pluginOpts: QwikPluginOptions = {
Expand Down Expand Up @@ -287,8 +283,6 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
clientDevInput = qwikPlugin.normalizePath(clientDevInput);
}

const vendorRoots = shouldFindVendors ? await findQwikRoots(sys, sys.cwd()) : [];
const vendorIds = vendorRoots.map((v) => v.id);
const isDevelopment = buildMode === 'development';
const qDevKey = 'globalThis.qDev';
const qTestKey = 'globalThis.qTest';
Expand All @@ -300,11 +294,11 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {

const updatedViteConfig: UserConfig = {
ssr: {
noExternal: [QWIK_CORE_ID, QWIK_CORE_SERVER, QWIK_BUILD_ID, ...vendorIds],
noExternal: [QWIK_CORE_ID, QWIK_CORE_SERVER, QWIK_BUILD_ID],
},
envPrefix: ['VITE_', 'PUBLIC_'],
resolve: {
dedupe: [...DEDUPE, ...vendorIds],
dedupe: [...DEDUPE],
conditions: buildMode === 'production' && target === 'client' ? ['min'] : [],
},
esbuild:
Expand All @@ -326,7 +320,6 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any {
QWIK_JSX_DEV_RUNTIME_ID,
QWIK_BUILD_ID,
QWIK_CLIENT_MANIFEST_ID,
...vendorIds,
],
},
build: {
Expand Down Expand Up @@ -823,94 +816,6 @@ export async function render(document, rootNode, opts) {
}`;
}

async function findDepPkgJsonPath(sys: OptimizerSystem, dep: string, parent: string) {
const fs: typeof import('fs') = await sys.dynamicImport('node:fs');
let root = parent;
while (root) {
const pkg = sys.path.join(root, 'node_modules', dep, 'package.json');
try {
await fs.promises.access(pkg);
// use 'node:fs' version to match 'vite:resolve' and avoid realpath.native quirk
// https://github.com/sveltejs/vite-plugin-svelte/issues/525#issuecomment-1355551264
return fs.promises.realpath(pkg);
} catch {
//empty
}
const nextRoot = sys.path.dirname(root);
if (nextRoot === root) {
break;
}
root = nextRoot;
}
return undefined;
}

const findQwikRoots = async (
sys: OptimizerSystem,
packageJsonDir: string
): Promise<QwikPackages[]> => {
const paths = new Map<string, string>();
if (sys.env === 'node') {
const fs: typeof import('fs') = await sys.dynamicImport('node:fs');
let prevPackageJsonDir: string | undefined;
do {
try {
const data = await fs.promises.readFile(sys.path.join(packageJsonDir, 'package.json'), {
encoding: 'utf-8',
});

try {
const packageJson = JSON.parse(data);
const dependencies = packageJson['dependencies'];
const devDependencies = packageJson['devDependencies'];

const packages: string[] = [];
if (typeof dependencies === 'object') {
packages.push(...Object.keys(dependencies));
}
if (typeof devDependencies === 'object') {
packages.push(...Object.keys(devDependencies));
}

const basedir = sys.cwd();
await Promise.all(
packages.map(async (id) => {
const pkgJsonPath = await findDepPkgJsonPath(sys, id, basedir);
if (pkgJsonPath) {
const pkgJsonContent = await fs.promises.readFile(pkgJsonPath, 'utf-8');
const pkgJson = JSON.parse(pkgJsonContent);
const qwikPath = pkgJson['qwik'];
if (!qwikPath) {
return;
}
// Support multiple paths
const allPaths = Array.isArray(qwikPath) ? qwikPath : [qwikPath];
for (const p of allPaths) {
paths.set(
await fs.promises.realpath(sys.path.resolve(sys.path.dirname(pkgJsonPath), p)),
id
);
}
}
})
);
} catch (e) {
console.error(e);
}
} catch (e) {
// ignore errors if package.json not found
}
prevPackageJsonDir = packageJsonDir;
packageJsonDir = sys.path.dirname(packageJsonDir);
} while (packageJsonDir !== prevPackageJsonDir);
}
return Array.from(paths).map(([path, id]) => ({ path, id }));
};

export const isNotNullable = <T>(v: T): v is NonNullable<T> => {
return v != null;
};

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

Expand Down
17 changes: 2 additions & 15 deletions starters/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ const appNames = readdirSync(startersAppsDir).filter(
(p) => statSync(join(startersAppsDir, p)).isDirectory() && p !== "base",
);

const rootDir = resolve(__dirname, "..");
const packagesDir = resolve(rootDir, "packages");
const qwikCityMjs = join(packagesDir, "qwik-city", "lib", "index.qwik.mjs");

/** Used when qwik-city server is enabled */
const qwikCityVirtualEntry = "@city-ssr-entry";
const entrySsrFileName = "entry.ssr.tsx";
Expand Down Expand Up @@ -208,16 +204,7 @@ export {
plugins: [
...plugins,
optimizer.qwikVite({
/**
* normally qwik finds qwik-city via package.json but we don't want that
* because it causes it try try to lookup the special qwik city imports
* even when we're not actually importing qwik-city
*/
disableVendorScan: true,
vendorRoots: enableCityServer ? [qwikCityMjs] : [],
entryStrategy: {
type: "segment",
},
entryStrategy: { type: "segment" },
client: {
manifestOutput(manifest) {
clientManifest = manifest;
Expand Down Expand Up @@ -266,7 +253,7 @@ function removeDir(dir: string) {
}
});
rmSync(dir);
} catch (e) {
} catch {
/**/
}
}
Expand Down
Loading