) : null}
- {store.selectedOutputPanel === 'symbols' ? (
-
) : null}
{store.selectedOutputPanel === 'clientBundles' ? (
@@ -120,7 +192,7 @@ export const ReplOutputPanel = component$(({ input, store }: ReplOutputPanelProp
{store.selectedOutputPanel === 'diagnostics' ? (
- {diagnosticsLen === 0 ? (
+ {diagnosticsLen.value === 0 ? (
- No Reported Diagnostics -
) : (
[...store.diagnostics, ...store.monacoDiagnostics].map((d, key) => (
diff --git a/packages/docs/src/repl/repl-output-segments.tsx b/packages/docs/src/repl/repl-output-segments.tsx
new file mode 100644
index 00000000000..544cf5c109a
--- /dev/null
+++ b/packages/docs/src/repl/repl-output-segments.tsx
@@ -0,0 +1,73 @@
+import { $, component$, useSignal } from '@qwik.dev/core';
+import type { TransformModule } from '@qwik.dev/core/optimizer';
+import { CodeBlock } from '../components/code-block/code-block';
+const FILE_MODULE_DIV_ID = 'file-modules-symbol';
+
+export const ReplOutputSegments = component$(({ outputs }: ReplOutputSegmentsProps) => {
+ const selectedPath = useSignal(outputs.length ? outputs[0].path : '');
+ const pathInView$ = $((path: string) => {
+ selectedPath.value = path;
+ });
+
+ return (
+
+
+
+
+ {outputs.map((o, i) => (
+
+ ))}
+
+
+
+ {outputs
+ .filter((o) => !!o.segment)
+ .map((o, i) => (
+
+
+
{o.segment!.canonicalFilename}
+ {o.segment!.paramNames && (
+
+ Params: {o.segment!.paramNames.join(', ')}
+
+ )}
+ {o.segment!.captureNames && (
+
+ Captures: {o.segment!.captureNames.join(', ')}
+
+ )}
+
+
+
+
+
+ ))}
+
+
+ );
+});
+
+interface ReplOutputSegmentsProps {
+ outputs: TransformModule[];
+}
diff --git a/packages/docs/src/repl/repl-output-symbols.tsx b/packages/docs/src/repl/repl-output-symbols.tsx
deleted file mode 100644
index 47846d85e6e..00000000000
--- a/packages/docs/src/repl/repl-output-symbols.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import type { TransformModule } from '@builder.io/qwik/optimizer';
-import { CodeBlock } from '../components/code-block/code-block';
-import { $, component$, useSignal } from '@builder.io/qwik';
-const FILE_MODULE_DIV_ID = 'file-modules-symbol';
-
-export const ReplOutputSymbols = component$(({ outputs }: ReplOutputSymbolsProps) => {
- const selectedPath = useSignal(outputs.length ? outputs[0].path : '');
- const pathInView$ = $((path: string) => {
- selectedPath.value = path;
- });
-
- return (
-
-
-
-
- {outputs.map((o, i) => (
-
- ))}
-
-
-
- {outputs
- .filter((o) => !!o.segment)
- .map((o, i) => (
-
-
- {o.segment?.canonicalFilename}
-
-
-
-
-
- ))}
-
-
- );
-});
-
-interface ReplOutputSymbolsProps {
- outputs: TransformModule[];
-}
diff --git a/packages/docs/src/repl/repl-output-update.ts b/packages/docs/src/repl/repl-output-update.ts
index 1fe666a0dc6..f1d074841e5 100644
--- a/packages/docs/src/repl/repl-output-update.ts
+++ b/packages/docs/src/repl/repl-output-update.ts
@@ -1,29 +1,45 @@
import type { ReplResult, ReplStore } from './types';
// TODO fix useStore to recursively notify subscribers
-const deepUpdate = (prev: any, next: any) => {
+const deepUpdate = (prev: any, next: any, matcher?: (a: any, b: any) => boolean) => {
for (const key in next) {
if (prev[key] && typeof next[key] === 'object' && typeof prev[key] === 'object') {
deepUpdate(prev[key], next[key]);
} else {
- prev[key] = next[key];
+ if (prev[key] !== next[key]) {
+ prev[key] = next[key];
+ }
}
}
- for (const key in prev) {
- if (!(key in next)) {
- delete prev[key];
+ if (Array.isArray(prev)) {
+ for (const item of prev) {
+ if (!next.some((nextItem: any) => (matcher ? matcher(nextItem, item) : nextItem === item))) {
+ prev.splice(prev.indexOf(item), 1);
+ }
+ }
+ } else {
+ for (const key in prev) {
+ if (!(key in next)) {
+ delete prev[key];
+ }
}
}
};
+const matchByPath = (a: any, b: any) => a.path === b.path;
+
export const updateReplOutput = async (store: ReplStore, result: ReplResult) => {
- store.diagnostics = result.diagnostics;
+ deepUpdate(store.diagnostics, result.diagnostics);
+ if (store.htmlResult.rawHtml !== result.htmlResult.rawHtml) {
+ store.htmlResult.rawHtml = result.htmlResult.rawHtml;
+ store.htmlResult.prettyHtml = result.htmlResult.prettyHtml;
+ }
- if (store.diagnostics.length === 0) {
- store.html = result.html;
- deepUpdate(store.transformedModules, result.transformedModules);
- deepUpdate(store.clientBundles, result.clientBundles);
- deepUpdate(store.ssrModules, result.ssrModules);
+ if (result.diagnostics.length === 0) {
+ deepUpdate(store.htmlResult, result.htmlResult);
+ deepUpdate(store.transformedModules, result.transformedModules, matchByPath);
+ deepUpdate(store.clientBundles, result.clientBundles, matchByPath);
+ deepUpdate(store.ssrModules, result.ssrModules, matchByPath);
if (
result.events.length !== store.events.length ||
result.events.some((ev, i) => ev?.start !== store.events[i]?.start)
diff --git a/packages/docs/src/repl/repl-share-url.ts b/packages/docs/src/repl/repl-share-url.ts
index 6de7babc17e..2ade4edff89 100644
--- a/packages/docs/src/repl/repl-share-url.ts
+++ b/packages/docs/src/repl/repl-share-url.ts
@@ -85,6 +85,10 @@ export const strToFiles = (str: string) => {
// You can add new entries to the beginning though.
export const dictionary = strToU8(
filesToStr([
+ {
+ path: '/app.tsx',
+ code: `import { component$ } from '@qwik.dev/core';\n\nexport default component$(() => {\n return (\n
\n
Hello from Qwik!
\n \n );\n`,
+ },
{
path: '',
// Extra words to help with compression
@@ -98,7 +102,7 @@ export const dictionary = strToU8(
// You need to add a new section like this before this section instead
code: `
props: class return ( story component$( store string state export const span type href={ page strong count useSignal< useStore< qwik import { } from searchInput console.log( searchResults builder useTask$( stories style={ news export default data track onClick$= new nav map link debounced controller user useStyles$( useStylesScoped$( url title timeoutId time_ago second response Date.now() minute main item interface hour disabled aria any State update transform the target suggestion setTimeout selectedValue rotate render people number list label https:// header deg debouncedGetPeople debounce component comments_count comments clock background await new Promise args SuggestionsListComponent IStory IState IComment GrandChild Clock Child AutoComplete 360 yellow with view useVisibleTask$( true tmrId timer then swapi styles signal section search results resolve rel prev points parsedResponse null noreferrer name more length json job items isServer index github getPeople function fetch example domain dev delay css container com click clearTimeout async api _blank Star Wars API This The StoryPreview Stories ReturnType Qwik App Page Nav HackerNewsCSS AbortController server$( routeAction$( routeLoader$( useContent( useDocumentHead( useLocation( useNavigate( validator$( zod$( noSerialize( useComputed$( useOnDocument( useOnWindow( useResource$( useContext( useContextProvider( createContextId<`,
},
- // The default hello world app + supporting files
+ // The old default hello world app + supporting files
{
path: '/app.tsx',
code: `import { component$ } from '@builder.io/qwik';\n\nexport default component$(() => {\n return
Hello Qwik
;\n});\n`,
diff --git a/packages/docs/src/repl/repl-share-url.unit.ts b/packages/docs/src/repl/repl-share-url.unit.ts
index 6d1dec380bc..3c90defd60c 100644
--- a/packages/docs/src/repl/repl-share-url.unit.ts
+++ b/packages/docs/src/repl/repl-share-url.unit.ts
@@ -1,13 +1,14 @@
-import { assert, test } from 'vitest';
+import { strFromU8 } from 'fflate';
+import { assert, expect, test } from 'vitest';
import {
- filesToStr,
- strToFiles,
- createPlaygroundShareUrl,
compressFiles,
- parseCompressedFiles,
+ createPlaygroundShareUrl,
dictionary,
+ filesToStr,
+ parseCompressedFiles,
+ parsePlaygroundShareUrl,
+ strToFiles,
} from './repl-share-url';
-import { strFromU8 } from 'fflate';
const data = {
version: '1.2.3',
@@ -64,8 +65,85 @@ test('createPlaygroundShareUrl 2', () => {
});
test('dictionary is unchanged', () => {
- assert.equal(
- strFromU8(dictionary),
- "0||1448|
props: class return ( story component$( store string state export const span type href={ page strong count useSignal< useStore< qwik import { } from searchInput console.log( searchResults builder useTask$( stories style={ news export default data track onClick$= new nav map link debounced controller user useStyles$( useStylesScoped$( url title timeoutId time_ago second response Date.now() minute main item interface hour disabled aria any State update transform the target suggestion setTimeout selectedValue rotate render people number list label https:// header deg debouncedGetPeople debounce component comments_count comments clock background await new Promise args SuggestionsListComponent IStory IState IComment GrandChild Clock Child AutoComplete 360 yellow with view useVisibleTask$( true tmrId timer then swapi styles signal section search results resolve rel prev points parsedResponse null noreferrer name more length json job items isServer index github getPeople function fetch example domain dev delay css container com click clearTimeout async api _blank Star Wars API This The StoryPreview Stories ReturnType Qwik App Page Nav HackerNewsCSS AbortController server$( routeAction$( routeLoader$( useContent( useDocumentHead( useLocation( useNavigate( validator$( zod$( noSerialize( useComputed$( useOnDocument( useOnWindow( useResource$( useContext( useContextProvider( createContextId<|8|/app.tsx|114|import { component$ } from '@builder.io/qwik';\n\nexport default component$(() => {\n return
Hello Qwik
;\n});\n|17|/entry.server.tsx|201|import { renderToString, type RenderOptions } from '@builder.io/qwik/server';\nimport { Root } from './root';\n\nexport default function (opts: RenderOptions) {\n return renderToString(
, opts);\n}\n|9|/root.tsx|192|import App from './app';\n\nexport const Root = () => {\n return (\n <>\n \n
Hello Qwik\n \n \n
\n \n >\n );\n};\n"
+ const dictionaryAsString = strFromU8(dictionary);
+ expect(dictionaryAsString).toMatchInlineSnapshot(`
+ "8|/app.tsx|149|import { component$ } from '@qwik.dev/core';
+
+ export default component$(() => {
+ return (
+
+
Hello from Qwik!
+
+ );
+ |0||1448|
props: class return ( story component$( store string state export const span type href={ page strong count useSignal< useStore< qwik import { } from searchInput console.log( searchResults builder useTask$( stories style={ news export default data track onClick$= new nav map link debounced controller user useStyles$( useStylesScoped$( url title timeoutId time_ago second response Date.now() minute main item interface hour disabled aria any State update transform the target suggestion setTimeout selectedValue rotate render people number list label https:// header deg debouncedGetPeople debounce component comments_count comments clock background await new Promise args SuggestionsListComponent IStory IState IComment GrandChild Clock Child AutoComplete 360 yellow with view useVisibleTask$( true tmrId timer then swapi styles signal section search results resolve rel prev points parsedResponse null noreferrer name more length json job items isServer index github getPeople function fetch example domain dev delay css container com click clearTimeout async api _blank Star Wars API This The StoryPreview Stories ReturnType Qwik App Page Nav HackerNewsCSS AbortController server$( routeAction$( routeLoader$( useContent( useDocumentHead( useLocation( useNavigate( validator$( zod$( noSerialize( useComputed$( useOnDocument( useOnWindow( useResource$( useContext( useContextProvider( createContextId<|8|/app.tsx|114|import { component$ } from '@builder.io/qwik';
+
+ export default component$(() => {
+ return
Hello Qwik
;
+ });
+ |17|/entry.server.tsx|201|import { renderToString, type RenderOptions } from '@builder.io/qwik/server';
+ import { Root } from './root';
+
+ export default function (opts: RenderOptions) {
+ return renderToString(
, opts);
+ }
+ |9|/root.tsx|192|import App from './app';
+
+ export const Root = () => {
+ return (
+ <>
+
+
Hello Qwik
+
+
+
+
+ >
+ );
+ };
+ "
+ `);
+});
+
+test('previous URLs still work', () => {
+ expect(parsePlaygroundShareUrl('f=G000o4mG5EQDAA')).toHaveProperty(
+ 'files',
+ // DO NOT UPDATE THIS TEST - all these URLs must work forever
+ expect.arrayContaining([
+ expect.objectContaining({
+ path: '/app.tsx',
+ code: "import { component$ } from '@builder.io/qwik';\n\nexport default component$(() => {\n return
Hello Qwik
;\n});\n",
+ }),
+ ])
+ );
+ expect(
+ parsePlaygroundShareUrl(
+ 'f=Q0o0xgaW2BKNDrDkqNCB15QUpyFIgKTl51uBeGA%2BKO%2BBIwaW0W1A6SI%2FDWQzyKm1wKBDVwyU0lAqUNJRqE4GFc3AqLNSCnENDlGq1QTpAGJ43a5RDa6oa0FOgBsDbxkAXQIMCqAWMIktXqqBSvRgNoNMRg7C0XQ%2FJNM9AA'
+ )
+ ).toHaveProperty(
+ 'files',
+ // DO NOT UPDATE THIS TEST - all these URLs must work forever
+ expect.arrayContaining([
+ expect.objectContaining({
+ path: '/app.tsx',
+ code: `import { component$, jsx, useTask$ } from '@builder.io/qwik';
+
+export default component$(() => {
+ const foo:{
+ contents: ReturnType
+ } = {
+ contents: jsx("p", {children:"TEST"})
+ }
+ useTask$(({track}) =>{
+ console.log(foo);
+ });
+ return (
+ <>
+ {foo.contents}
+ >
+ );
+});
+`,
+ }),
+ ])
);
});
diff --git a/packages/docs/src/repl/repl-tab-button.tsx b/packages/docs/src/repl/repl-tab-button.tsx
index 16274c8cac8..824514e2bb1 100644
--- a/packages/docs/src/repl/repl-tab-button.tsx
+++ b/packages/docs/src/repl/repl-tab-button.tsx
@@ -1,4 +1,4 @@
-import type { PropsOf, Component } from '@builder.io/qwik';
+import type { PropsOf, Component } from '@qwik.dev/core';
import { CloseIcon } from '../components/svgs/close-icon';
export const ReplTabButton: Component = (props) => {
diff --git a/packages/docs/src/repl/repl-version.ts b/packages/docs/src/repl/repl-version.ts
index 40608bbac0b..0a659d970c7 100644
--- a/packages/docs/src/repl/repl-version.ts
+++ b/packages/docs/src/repl/repl-version.ts
@@ -3,7 +3,7 @@ import { QWIK_PKG_NAME, bundled } from './bundled';
const bundledVersion = bundled[QWIK_PKG_NAME].version;
// The golden oldies
-const keepList = new Set('1.0.0,1.1.5,1.2.13,1.4.5'.split(','));
+const keepList = new Set('1.0.0,1.1.5,1.2.13,1.4.5,1.5.7,1.6.0,1.7.3,1.8.0,1.9.0'.split(','));
// The bad apples - add versions that break the REPL here
const blockList = new Set(
@@ -97,7 +97,7 @@ export const getReplVersion = async (version: string | undefined, offline: boole
});
versions.unshift('bundled');
- if (!hasVersion || !version) {
+ if ((!offline && !hasVersion) || !version) {
version = 'bundled';
}
@@ -113,11 +113,11 @@ const isExpiredNpmData = (npmData: NpmData | null) => {
return true;
};
-const QWIK_NPM_DATA = `https://data.jsdelivr.com/v1/package/npm/@builder.io/qwik`;
+const QWIK_NPM_DATA = `https://data.jsdelivr.com/v1/package/npm/@qwik.dev/core`;
const NPM_STORAGE_KEY = `qwikNpmData`;
-// https://data.jsdelivr.com/v1/package/npm/@builder.io/qwik
+// https://data.jsdelivr.com/v1/package/npm/@qwik.dev/core
interface NpmData {
tags: { latest: string; next: string };
versions: string[];
diff --git a/packages/docs/src/repl/repl.css b/packages/docs/src/repl/repl.css
index f5e8e437b4b..46517a129aa 100644
--- a/packages/docs/src/repl/repl.css
+++ b/packages/docs/src/repl/repl.css
@@ -199,6 +199,15 @@
overflow: auto;
}
+.output-html .code-block-info {
+ display: block;
+ font-weight: bold;
+ background-color: rgb(33 104 170 / 15%);
+ padding: 5px 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
.output-html pre {
height: 100%;
}
@@ -230,7 +239,7 @@
.output-modules .file-tree {
padding: 0 15px 15px 15px;
grid-area: repl-file-tree;
- overflow-y: auto;
+ overflow: auto;
}
.output-modules .file-tree-header {
@@ -242,8 +251,6 @@
display: block;
margin: 4px 0px 2px 9px;
white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
}
.output-modules .file-tree-items a:hover,
@@ -270,8 +277,7 @@
margin-bottom: 15px;
background-color: rgb(33 104 170 / 15%);
padding: 5px 10px;
- overflow: hidden;
- text-overflow: ellipsis;
+ word-break: break-word;
}
.output-modules .file-size {
diff --git a/packages/docs/src/repl/repl.tsx b/packages/docs/src/repl/repl.tsx
index 5213ec856eb..455d465cdc6 100644
--- a/packages/docs/src/repl/repl.tsx
+++ b/packages/docs/src/repl/repl.tsx
@@ -1,21 +1,21 @@
import {
+ $,
component$,
+ isServer,
noSerialize,
- useStyles$,
useStore,
+ useStyles$,
useTask$,
useVisibleTask$,
- $,
-} from '@builder.io/qwik';
+} from '@qwik.dev/core';
+import { QWIK_PKG_NAME, QWIK_PKG_NAME_V1, bundled, getNpmCdnUrl } from './bundled';
+import { ReplDetailPanel } from './repl-detail-panel';
import { ReplInputPanel } from './repl-input-panel';
import { ReplOutputPanel } from './repl-output-panel';
-import styles from './repl.css?inline';
-import type { ReplStore, ReplUpdateMessage, ReplMessage, ReplAppInput } from './types';
-import { ReplDetailPanel } from './repl-detail-panel';
-import { getReplVersion } from './repl-version';
import { updateReplOutput } from './repl-output-update';
-import { QWIK_PKG_NAME, bundled, getNpmCdnUrl } from './bundled';
-import { isServer } from '@builder.io/qwik';
+import { getReplVersion } from './repl-version';
+import styles from './repl.css?inline';
+import type { ReplAppInput, ReplMessage, ReplStore, ReplUpdateMessage } from './types';
export const Repl = component$((props: ReplProps) => {
useStyles$(styles);
@@ -27,7 +27,10 @@ export const Repl = component$((props: ReplProps) => {
clientId: Math.round(Math.random() * Number.MAX_SAFE_INTEGER)
.toString(36)
.toLowerCase(),
- html: '',
+ htmlResult: {
+ rawHtml: '',
+ prettyHtml: '',
+ },
transformedModules: [],
clientBundles: [],
ssrModules: [],
@@ -79,10 +82,6 @@ export const Repl = component$((props: ReplProps) => {
useVisibleTask$(
async () => {
- if (isServer) {
- return;
- }
- // only run on the client
// Get the version asap, most likely it will be cached.
const v = await getReplVersion(input.version, true);
store.versions = v.versions;
@@ -169,9 +168,14 @@ const getDependencies = (input: ReplAppInput) => {
if (input.version !== 'bundled') {
const [M, m, p] = input.version.split('-')[0].split('.').map(Number);
const prefix = M > 1 || (M == 1 && (m > 7 || (m == 7 && p >= 2))) ? '/dist/' : '/';
- out[QWIK_PKG_NAME] = {
- version: input.version,
- };
+ // we must always provide the qwik.dev package so the worker can find the version
+ out[QWIK_PKG_NAME] = { version: input.version };
+ let bundles;
+ if (M < 2) {
+ bundles = out[QWIK_PKG_NAME_V1] = { version: input.version };
+ } else {
+ bundles = out[QWIK_PKG_NAME];
+ }
for (const p of [
`${prefix}core.cjs`,
`${prefix}core.mjs`,
@@ -181,7 +185,7 @@ const getDependencies = (input: ReplAppInput) => {
`/bindings/qwik.wasm.cjs`,
`/bindings/qwik_wasm_bg.wasm`,
]) {
- out[QWIK_PKG_NAME][p] = getNpmCdnUrl(bundled, QWIK_PKG_NAME, input.version, p);
+ bundles[p] = getNpmCdnUrl(bundled, QWIK_PKG_NAME, input.version, p);
}
}
return out;
diff --git a/packages/docs/src/repl/types.ts b/packages/docs/src/repl/types.ts
index 11768f1cc4a..fa032c7761f 100644
--- a/packages/docs/src/repl/types.ts
+++ b/packages/docs/src/repl/types.ts
@@ -1,10 +1,10 @@
-import type { NoSerialize, Signal } from '@builder.io/qwik';
+import type { NoSerialize, Signal } from '@qwik.dev/core';
import type {
Diagnostic,
QwikManifest,
QwikRollupPluginOptions,
TransformModule,
-} from '@builder.io/qwik/optimizer';
+} from '@qwik.dev/core/optimizer';
export interface ReplAppInput {
buildId: number;
@@ -27,7 +27,7 @@ export interface ReplInputOptions extends Omit {
@@ -44,7 +44,7 @@ export const appBundleSsr = async (options: ReplInputOptions, result: ReplResult
const loc = warning.loc;
if (loc && loc.file) {
diagnostic.file = loc.file;
- diagnostic.highlights.push({
+ diagnostic.highlights!.push({
startCol: loc.column,
endCol: loc.column + 1,
startLine: loc.line,
diff --git a/packages/docs/src/repl/worker/app-ssr-html.ts b/packages/docs/src/repl/worker/app-ssr-html.ts
index 71cfb3df0f7..3b37d63aa60 100644
--- a/packages/docs/src/repl/worker/app-ssr-html.ts
+++ b/packages/docs/src/repl/worker/app-ssr-html.ts
@@ -1,4 +1,4 @@
-import type { RenderOptions, RenderToStringResult } from '@builder.io/qwik/server';
+import type { RenderOptions, RenderToStringResult } from '@qwik.dev/core/server';
import type { ReplInputOptions, ReplResult } from '../types';
import type { QwikWorkerGlobal } from './repl-service-worker';
@@ -82,7 +82,7 @@ export const appSsrHtml = async (options: ReplInputOptions, cache: Cache, result
console.error = error;
console.debug = debug;
- result.html = ssrResult.html;
+ result.htmlResult.rawHtml = ssrResult.html;
result.events.push({
kind: 'pause',
@@ -94,12 +94,12 @@ export const appSsrHtml = async (options: ReplInputOptions, cache: Cache, result
if (options.buildMode !== 'production') {
try {
- const html = await self.prettier?.format(result.html, {
+ const html = await self.prettier?.format(result.htmlResult.rawHtml, {
parser: 'html',
plugins: self.prettierPlugins,
});
if (html) {
- result.html = html;
+ result.htmlResult.prettyHtml = html;
}
} catch (e) {
console.error(e);
diff --git a/packages/docs/src/repl/worker/app-update.ts b/packages/docs/src/repl/worker/app-update.ts
index e9f22157d67..b93ec29804a 100644
--- a/packages/docs/src/repl/worker/app-update.ts
+++ b/packages/docs/src/repl/worker/app-update.ts
@@ -15,7 +15,10 @@ export const appUpdate = async (
type: 'result',
clientId,
buildId: options.buildId,
- html: '',
+ htmlResult: {
+ rawHtml: '',
+ prettyHtml: '',
+ },
transformedModules: [],
clientBundles: [],
manifest: undefined,
diff --git a/packages/docs/src/repl/worker/repl-constants.ts b/packages/docs/src/repl/worker/repl-constants.ts
index 4cf1c064d3a..6bc35d8f9fd 100644
--- a/packages/docs/src/repl/worker/repl-constants.ts
+++ b/packages/docs/src/repl/worker/repl-constants.ts
@@ -1,4 +1,5 @@
-export const QWIK_PKG_NAME = '@builder.io/qwik';
+export const QWIK_PKG_NAME = '@qwik.dev/core';
+export const QWIK_PKG_NAME_V1 = '@builder.io/qwik';
export const QWIK_REPL_DEPS_CACHE = 'QwikReplDeps';
export const QWIK_REPL_RESULT_CACHE = 'QwikReplResults';
diff --git a/packages/docs/src/repl/worker/repl-dependencies.ts b/packages/docs/src/repl/worker/repl-dependencies.ts
index ad2bec490f9..1c42daddb3d 100644
--- a/packages/docs/src/repl/worker/repl-dependencies.ts
+++ b/packages/docs/src/repl/worker/repl-dependencies.ts
@@ -1,19 +1,26 @@
import type { ReplInputOptions } from '../types';
-import { QWIK_PKG_NAME, QWIK_REPL_DEPS_CACHE } from './repl-constants';
+import { QWIK_PKG_NAME, QWIK_PKG_NAME_V1, QWIK_REPL_DEPS_CACHE } from './repl-constants';
import type { QwikWorkerGlobal } from './repl-service-worker';
let options: ReplInputOptions;
let cache: Cache;
export const depResponse = async (pkgName: string, pkgPath: string) => {
- if (pkgName === QWIK_PKG_NAME && !pkgPath.startsWith('/bindings')) {
- const version = options.deps[pkgName].version;
+ let dep = options.deps[pkgName];
+ if (pkgName === QWIK_PKG_NAME) {
+ const version = dep.version;
const [M, m, p] = version.split('-')[0].split('.').map(Number);
- if (M > 1 || (M == 1 && (m > 7 || (m == 7 && p >= 2)))) {
- pkgPath = `/dist${pkgPath}`;
+ if (!pkgPath.startsWith('/bindings') && !pkgPath.startsWith('/handlers.mjs')) {
+ if (M > 1 || (M == 1 && (m > 7 || (m == 7 && p >= 2)))) {
+ pkgPath = `/dist${pkgPath}`;
+ }
+ }
+ if (version < '2') {
+ pkgName = QWIK_PKG_NAME_V1;
+ dep = options.deps[pkgName];
}
}
- const url = options.deps[pkgName][pkgPath];
+ const url = dep[pkgPath];
if (!url) {
throw new Error(`No URL given for dep: ${pkgName}${pkgPath}`);
}
@@ -51,7 +58,7 @@ const _loadDependencies = async (replOptions: ReplInputOptions) => {
isServer: true,
isBrowser: false,
isDev: false,
- } as typeof import('@builder.io/qwik/build') as any;
+ } as typeof self.qwikBuild;
const cachedCjsCode = `qwikWasmCjs${realQwikVersion}`;
const cachedWasmRsp = `qwikWasmRsp${realQwikVersion}`;
@@ -72,27 +79,29 @@ const _loadDependencies = async (replOptions: ReplInputOptions) => {
if (!isSameQwikVersion(self.qwikCore?.version)) {
await exec(QWIK_PKG_NAME, '/core.cjs');
if (self.qwikCore) {
- console.debug(`Loaded @builder.io/qwik: ${self.qwikCore.version}`);
+ console.debug(`Loaded ${QWIK_PKG_NAME}: ${self.qwikCore.version}`);
} else {
- throw new Error(`Unable to load @builder.io/qwik ${qwikVersion}`);
+ throw new Error(`Unable to load ${QWIK_PKG_NAME} ${qwikVersion}`);
}
}
if (!isSameQwikVersion(self.qwikOptimizer?.versions.qwik)) {
await exec(QWIK_PKG_NAME, '/optimizer.cjs');
if (self.qwikOptimizer) {
- console.debug(`Loaded @builder.io/qwik/optimizer: ${self.qwikOptimizer.versions.qwik}`);
+ console.debug(`Loaded ${QWIK_PKG_NAME}/optimizer: ${self.qwikOptimizer.versions.qwik}`);
} else {
- throw new Error(`Unable to load @builder.io/qwik/optimizer ${qwikVersion}`);
+ throw new Error(`Unable to load ${QWIK_PKG_NAME}/optimizer ${qwikVersion}`);
}
}
if (!isSameQwikVersion(self.qwikServer?.versions.qwik)) {
+ // clear out the require shim that is version specific
+ (globalThis as any).require = undefined;
await exec(QWIK_PKG_NAME, '/server.cjs');
if (self.qwikServer) {
- console.debug(`Loaded @builder.io/qwik/server: ${self.qwikServer.versions.qwik}`);
+ console.debug(`Loaded ${QWIK_PKG_NAME}/server: ${self.qwikServer.versions.qwik}`);
} else {
- throw new Error(`Unable to load @builder.io/qwik/server ${qwikVersion}`);
+ throw new Error(`Unable to load ${QWIK_PKG_NAME}/server ${qwikVersion}`);
}
}
diff --git a/packages/docs/src/repl/worker/repl-messenger.ts b/packages/docs/src/repl/worker/repl-messenger.ts
index 98a1f450709..d7c65d658bf 100644
--- a/packages/docs/src/repl/worker/repl-messenger.ts
+++ b/packages/docs/src/repl/worker/repl-messenger.ts
@@ -3,9 +3,13 @@ import { appUpdate } from './app-update';
export const receiveMessageFromMain = (ev: MessageEvent) => {
if (ev.data) {
- const msg: ReplMessage = JSON.parse(ev.data);
- if (msg.type === 'update') {
- appUpdate(ev.source as any as WindowClient, msg.clientId, msg.options);
+ try {
+ const msg: ReplMessage = JSON.parse(ev.data);
+ if (msg.type === 'update') {
+ appUpdate(ev.source as any as WindowClient, msg.clientId, msg.options);
+ }
+ } catch {
+ // ignore, probably some extension sending non-JSON data
}
}
};
diff --git a/packages/docs/src/repl/worker/repl-plugins.ts b/packages/docs/src/repl/worker/repl-plugins.ts
index 3866f685e84..a461f44cc3a 100644
--- a/packages/docs/src/repl/worker/repl-plugins.ts
+++ b/packages/docs/src/repl/worker/repl-plugins.ts
@@ -1,9 +1,18 @@
+import type { QwikRollupPluginOptions } from '@qwik.dev/core/optimizer';
import type { Plugin } from 'rollup';
-import type { QwikRollupPluginOptions } from '@builder.io/qwik/optimizer';
-import type { QwikWorkerGlobal } from './repl-service-worker';
import type { MinifyOptions } from 'terser';
import type { ReplInputOptions } from '../types';
import { depResponse } from './repl-dependencies';
+import type { QwikWorkerGlobal } from './repl-service-worker';
+
+/**
+ * Use paths that look like the paths ones from node modules. The plugin uses the paths to recognize
+ * the Qwik packages.
+ */
+const corePath = '/@qwik.dev/core/dist/core.mjs';
+const handlersPath = '/@qwik.dev/core/handlers.mjs';
+const serverPath = '/@qwik.dev/core/dist/server.mjs';
+const preloaderPath = '/@qwik.dev/core/dist/preloader.mjs';
export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 'ssr'): Plugin => {
const srcInputs = options.srcInputs;
@@ -19,18 +28,22 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's
if (!importer) {
return id;
}
- if (
- id === '@builder.io/qwik' ||
- id === '@builder.io/qwik/jsx-runtime' ||
- id === '@builder.io/qwik/jsx-dev-runtime'
- ) {
- return '\0qwikCore';
- }
- if (id === '@builder.io/qwik/server') {
- return '\0qwikServer';
- }
- if (id === '@builder.io/qwik/preloader') {
- return '\0qwikPreloader';
+ const match = id.match(/(@builder\.io\/qwik|@qwik\.dev\/core)(.*)/);
+ if (match) {
+ const pkgPath = match[2];
+ if (pkgPath === '/server') {
+ return serverPath;
+ }
+ if (pkgPath === '/preloader') {
+ return preloaderPath;
+ }
+ if (pkgPath === '/handlers.mjs') {
+ return handlersPath;
+ }
+ if (/^(|\/jsx(-dev)?-runtime|\/internal)$/.test(pkgPath)) {
+ return corePath;
+ }
+ console.error(`Unknown package ${id}`, match);
}
// Simple relative file resolution
if (id.startsWith('./')) {
@@ -51,29 +64,35 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's
return input.code;
}
if (buildMode === 'ssr') {
- if (id === '\0qwikCore') {
+ if (id === corePath || id === handlersPath) {
return getRuntimeBundle('qwikCore');
}
- if (id === '\0qwikServer') {
+ if (id === serverPath) {
return getRuntimeBundle('qwikServer');
}
}
- if (id === '\0qwikCore') {
+ if (id === corePath) {
if (options.buildMode === 'production') {
- const rsp = await depResponse('@builder.io/qwik', '/core.min.mjs');
+ const rsp = await depResponse('@qwik.dev/core', '/core.min.mjs');
if (rsp) {
return rsp.text();
}
}
- const rsp = await depResponse('@builder.io/qwik', '/core.mjs');
+ const rsp = await depResponse('@qwik.dev/core', '/core.mjs');
if (rsp) {
return rsp.text();
}
throw new Error(`Unable to load Qwik core`);
}
- if (id === '\0qwikPreloader') {
- const rsp = await depResponse('@builder.io/qwik', '/preloader.mjs');
+ if (id === preloaderPath) {
+ const rsp = await depResponse('@qwik.dev/core', '/preloader.mjs');
+ if (rsp) {
+ return rsp.text();
+ }
+ }
+ if (id === handlersPath) {
+ const rsp = await depResponse('@qwik.dev/core', '/handlers.mjs');
if (rsp) {
return rsp.text();
}
diff --git a/packages/docs/src/repl/worker/repl-request-handler.ts b/packages/docs/src/repl/worker/repl-request-handler.ts
index 87555ce9138..872119fd967 100644
--- a/packages/docs/src/repl/worker/repl-request-handler.ts
+++ b/packages/docs/src/repl/worker/repl-request-handler.ts
@@ -30,20 +30,6 @@ export const requestHandler = (ev: FetchEvent) => {
return htmlRsp;
}
- // app client modules
- // const replEvent: ReplEventMessage = {
- // type: 'event',
- // clientId,
- // event: {
- // kind: 'client-module',
- // scope: 'network',
- // message: [reqUrl.pathname + reqUrl.search],
- // start: performance.now(),
- // },
- // };
-
- // sendMessageToReplServer(replEvent);
-
return rsp;
}
@@ -169,5 +155,9 @@ const injectDevHtml = (clientId: string, html?: string) => {
}, true);
})();`;
- return `${html || ''}`;
+ if (!html) {
+ return '';
+ }
+
+ return html.replace(/<\/body>/i, `