From 79c09104abeefc619ec5f42df97f11789e006faa Mon Sep 17 00:00:00 2001 From: Manu MA Date: Mon, 23 May 2022 13:21:30 -0700 Subject: [PATCH 1/3] fix: live reloading --- packages/docs/package.json | 2 +- packages/qwik/src/core/api.md | 2 +- .../qwik/src/core/component/component-ctx.ts | 33 ++++++++++----- packages/qwik/src/core/import/qrl-class.ts | 5 ++- packages/qwik/src/core/import/qrl.public.ts | 2 +- packages/qwik/src/core/object/q-object.ts | 9 +++++ packages/qwik/src/core/util/promises.ts | 5 ++- .../qwik/src/optimizer/src/plugins/plugin.ts | 40 ++++++++++--------- .../qwik/src/optimizer/src/plugins/rollup.ts | 12 +++--- .../qwik/src/optimizer/src/plugins/vite.ts | 14 ++++--- yarn.lock | 14 +++---- 11 files changed, 85 insertions(+), 53 deletions(-) diff --git a/packages/docs/package.json b/packages/docs/package.json index a9a2b00436f..33994ba0367 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -19,7 +19,7 @@ }, "devDependencies": { "@builder.io/partytown": "^0.5.4", - "@builder.io/qwik": "0.0.20-5", + "@builder.io/qwik": "0.0.20-7", "@builder.io/qwik-city": "0.0.5", "@cloudflare/kv-asset-handler": "0.2.0", "@cloudflare/workers-types": "^3.10.0", diff --git a/packages/qwik/src/core/api.md b/packages/qwik/src/core/api.md index 997e91dd914..5277a9275b3 100644 --- a/packages/qwik/src/core/api.md +++ b/packages/qwik/src/core/api.md @@ -393,7 +393,7 @@ export interface QRL { // (undocumented) __brand__QRL__: TYPE; // (undocumented) - invoke(...args: TYPE extends (...args: infer ARGS) => any ? ARGS : never): TYPE extends (...args: any[]) => infer RETURN ? ValueOrPromise : never; + invoke(...args: TYPE extends (...args: infer ARGS) => any ? ARGS : never): Promise infer RETURN ? RETURN : never>; // (undocumented) invokeFn(el?: Element, context?: InvokeContext, beforeFn?: () => void): TYPE extends (...args: infer ARGS) => infer RETURN ? (...args: ARGS) => ValueOrPromise : never; // (undocumented) diff --git a/packages/qwik/src/core/component/component-ctx.ts b/packages/qwik/src/core/component/component-ctx.ts index 091bfc480c3..d532e5b9c51 100644 --- a/packages/qwik/src/core/component/component-ctx.ts +++ b/packages/qwik/src/core/component/component-ctx.ts @@ -8,7 +8,7 @@ import { isStyleTask, newInvokeContext } from '../use/use-core'; import { getProps, QContext } from '../props/props'; import { processNode } from '../render/jsx/jsx-runtime'; import { wrapSubscriber } from '../use/use-subscriber'; -import { logDebug } from '../util/log'; +import { logDebug, logError } from '../util/log'; import type { ValueOrPromise } from '../util/types'; import { removeSub } from '../object/q-object'; @@ -42,15 +42,11 @@ export const renderComponent = (rctx: RenderContext, ctx: QContext): ValueOrProm ctx.refMap.array.forEach((obj) => { removeSub(obj, hostElement); }); - const onRenderFn = onRenderQRL.invokeFn(rctx.containerEl, invocatinContext); - // Execution of the render function - const renderPromise = onRenderFn(wrapSubscriber(getProps(ctx), hostElement)); + const onRenderFn = onRenderQRL.invokeFn(rctx.containerEl, invocatinContext); - // Wait for results - return then(renderPromise, (jsxNode) => { + function postRender() { rctx.hostElements.add(hostElement); - const waitOnPromise = promiseAll(waitOn); return then(waitOnPromise, (waitOnResolved) => { waitOnResolved.forEach((task) => { @@ -81,7 +77,26 @@ export const renderComponent = (rctx: RenderContext, ctx: QContext): ValueOrProm } componentCtx.slots = []; newCtx.components.push(componentCtx); - return visitJsxNode(newCtx, hostElement, processNode(jsxNode), false); }); - }); + } + + try { + // Execution of the render function + const renderPromise = onRenderFn(wrapSubscriber(getProps(ctx), hostElement)); + + // Wait for results + return then( + renderPromise, + (jsxNode) => { + return then(postRender(), () => { + return visitJsxNode(newCtx, hostElement, processNode(jsxNode), false); + }); + }, + (err) => { + logError(err); + } + ); + } catch (err) { + logError(err); + } }; diff --git a/packages/qwik/src/core/import/qrl-class.ts b/packages/qwik/src/core/import/qrl-class.ts index 23d7166e1c8..b844c519864 100644 --- a/packages/qwik/src/core/import/qrl-class.ts +++ b/packages/qwik/src/core/import/qrl-class.ts @@ -69,9 +69,10 @@ class QRL implements IQRL { return copy; } - invoke(...args: TYPE extends (...args: infer ARGS) => any ? ARGS : never) { + async invoke(...args: TYPE extends (...args: infer ARGS) => any ? ARGS : never) { const fn = this.invokeFn(); - return fn(...args) as any; + const result = await fn(...args); + return result; } serialize(options?: QRLSerializeOptions) { diff --git a/packages/qwik/src/core/import/qrl.public.ts b/packages/qwik/src/core/import/qrl.public.ts index 906fc844119..c78f129535a 100644 --- a/packages/qwik/src/core/import/qrl.public.ts +++ b/packages/qwik/src/core/import/qrl.public.ts @@ -132,7 +132,7 @@ export interface QRL { resolve(container?: Element): Promise; invoke( ...args: TYPE extends (...args: infer ARGS) => any ? ARGS : never - ): TYPE extends (...args: any[]) => infer RETURN ? ValueOrPromise : never; + ): Promise infer RETURN ? RETURN : never>; invokeFn( el?: Element, diff --git a/packages/qwik/src/core/object/q-object.ts b/packages/qwik/src/core/object/q-object.ts index 5972b2acdf0..cc4f1b68883 100644 --- a/packages/qwik/src/core/object/q-object.ts +++ b/packages/qwik/src/core/object/q-object.ts @@ -15,6 +15,7 @@ import { debugStringify } from '../util/stringify'; import { WatchDescriptor, WatchFlags } from '../watch/watch.public'; import type { Subscriber } from '../use/use-subscriber'; import { tryGetContext } from '../props/props'; +import { RenderEvent } from '../util/markers'; export type ObjToProxyMap = WeakMap; export type QObject = T & { __brand__: 'QObject' }; @@ -187,6 +188,14 @@ class ReadWriteProxyHandler implements ProxyHandler { const unwrappedNewValue = unwrapProxy(newValue); if (qDev) { verifySerializable(unwrappedNewValue); + const invokeCtx = tryGetInvokeContext(); + if (invokeCtx && invokeCtx.event === RenderEvent) { + logWarn( + 'State mutation inside render function. Move mutation to useWatch(), useClientEffect() or useServerMount()', + invokeCtx.hostElement, + prop + ); + } } const isArray = Array.isArray(target); if (isArray) { diff --git a/packages/qwik/src/core/util/promises.ts b/packages/qwik/src/core/util/promises.ts index a3cc156cc57..b5d247160c0 100644 --- a/packages/qwik/src/core/util/promises.ts +++ b/packages/qwik/src/core/util/promises.ts @@ -27,9 +27,10 @@ export function isPromise(value: any): value is Promise { export const then = ( promise: ValueOrPromise, - thenFn: (arg: Awaited) => ValueOrPromise + thenFn: (arg: Awaited) => ValueOrPromise, + rejectFn?: (err: any) => any ): ValueOrPromise => { - return isPromise(promise) ? promise.then(thenFn as any) : thenFn(promise as any); + return isPromise(promise) ? promise.then(thenFn as any, rejectFn) : thenFn(promise as any); }; export const promiseAll = (promises: T): ValueOrPromise => { diff --git a/packages/qwik/src/optimizer/src/plugins/plugin.ts b/packages/qwik/src/optimizer/src/plugins/plugin.ts index 429fa3742b0..ce63496751a 100644 --- a/packages/qwik/src/optimizer/src/plugins/plugin.ts +++ b/packages/qwik/src/optimizer/src/plugins/plugin.ts @@ -23,7 +23,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const transformedOutputs = new Map(); let internalOptimizer: Optimizer | null = null; - let addWatchFileCallback: (path: string) => void = () => {}; + let addWatchFileCallback: (ctx: any, path: string) => void = () => {}; let diagnosticsCallback: (d: Diagnostic[], optimizer: Optimizer) => void = () => {}; const opts: NormalizedQwikPluginOptions = { @@ -213,7 +213,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } }; - const buildStart = async () => { + const buildStart = async (_ctx: any) => { log(`buildStart()`, opts.buildMode, opts.forceFullBuild ? 'full build' : 'isolated build'); if (opts.forceFullBuild) { @@ -262,6 +262,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; const resolveId = async ( + _ctx: any, id: string, importer: string | undefined, _resolveIdOpts?: { ssr?: boolean } @@ -309,7 +310,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const transformedModule = transformedOutput[0]; const sideEffects = !transformedModule.isEntry || !transformedModule.hook; return { - id: tryId, + id: tryId + parsedId.query, moduleSideEffects: sideEffects, }; } @@ -319,7 +320,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { return null; }; - const load = async (id: string, loadOpts: { ssr?: boolean } = {}) => { + const load = async (_ctx: any, id: string, loadOpts: { ssr?: boolean } = {}) => { if (id === QWIK_BUILD_ID) { log(`load()`, QWIK_BUILD_ID, opts.buildMode); return { @@ -366,17 +367,23 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { return null; }; - const transform = async (code: string, id: string) => { + const transform = function (ctx: any, code: string, id: string) { if (opts.forceFullBuild) { // Only run when moduleIsolated === true return null; } - id = normalizePath(id); - const pregenerated = transformedOutputs.get(id); + const optimizer = getOptimizer(); + const path = getPath(); + + const { pathId } = parseId(id); + const { ext, dir, base } = path.parse(pathId); + + const normalizedID = normalizePath(pathId); + const pregenerated = transformedOutputs.get(normalizedID); if (pregenerated) { - log(`transform() pregenerated, addWatchFile`, id, pregenerated[1]); - addWatchFileCallback(pregenerated[1]); + log(`transform() pregenerated, addWatchFile`, normalizedID, pregenerated[1]); + addWatchFileCallback(ctx, pregenerated[1]); return { meta: { @@ -384,13 +391,6 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }, }; } - - const optimizer = getOptimizer(); - const path = getPath(); - - const { pathId } = parseId(id); - const { ext, dir, base } = path.parse(pathId); - if (TRANSFORM_EXTS[ext]) { log(`transform()`, 'Transforming', pathId); @@ -485,7 +485,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } }; - const onAddWatchFile = (cb: (path: string) => void) => { + const onAddWatchFile = (cb: (ctx: any, path: string) => void) => { addWatchFileCallback = cb; }; @@ -553,11 +553,13 @@ export const manifest = ${JSON.stringify(manifest)};\n`; } export function parseId(originalId: string) { - const [pathId, querystrings] = originalId.split('?'); + const [pathId, query] = originalId.split('?'); + const queryStr = query || ''; return { originalId, pathId, - params: new URLSearchParams(querystrings || ''), + query: queryStr, + params: new URLSearchParams(queryStr), }; } diff --git a/packages/qwik/src/optimizer/src/plugins/rollup.ts b/packages/qwik/src/optimizer/src/plugins/rollup.ts index 3d4c9d6a447..7d0a7ee88b3 100644 --- a/packages/qwik/src/optimizer/src/plugins/rollup.ts +++ b/packages/qwik/src/optimizer/src/plugins/rollup.ts @@ -79,7 +79,9 @@ export function qwikRollup(qwikRollupOpts: QwikRollupPluginOptions = {}): any { }, async buildStart() { - qwikPlugin.onAddWatchFile((p) => this.addWatchFile(p)); + qwikPlugin.onAddWatchFile((ctx, path) => { + ctx.addWatchFile(path); + }); qwikPlugin.onDiagnostics((diagnostics, optimizer) => { diagnostics.forEach((d) => { @@ -91,28 +93,28 @@ export function qwikRollup(qwikRollupOpts: QwikRollupPluginOptions = {}): any { }); }); - await qwikPlugin.buildStart(); + await qwikPlugin.buildStart(this); }, resolveId(id, importer) { if (id.startsWith('\0')) { return null; } - return qwikPlugin.resolveId(id, importer); + return qwikPlugin.resolveId(this, id, importer); }, load(id) { if (id.startsWith('\0')) { return null; } - return qwikPlugin.load(id); + return qwikPlugin.load(this, id); }, transform(code, id) { if (id.startsWith('\0')) { return null; } - return qwikPlugin.transform(code, id); + return qwikPlugin.transform(this, code, id); }, async generateBundle(_, rollupBundle) { diff --git a/packages/qwik/src/optimizer/src/plugins/vite.ts b/packages/qwik/src/optimizer/src/plugins/vite.ts index f8202d6111b..f17f96dce2d 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite.ts @@ -172,7 +172,9 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { async buildStart() { await qwikPlugin.validateSource(); - qwikPlugin.onAddWatchFile((path) => this.addWatchFile(path)); + qwikPlugin.onAddWatchFile((ctx, path) => { + ctx.addWatchFile(path); + }); qwikPlugin.onDiagnostics((diagnostics, optimizer) => { diagnostics.forEach((d) => { @@ -184,7 +186,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { }); }); - await qwikPlugin.buildStart(); + await qwikPlugin.buildStart(this); }, resolveId(id, importer, resolveIdOpts) { @@ -194,7 +196,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { if (isClientDevOnly && id === VITE_CLIENT_MODULE) { return id; } - return qwikPlugin.resolveId(id, importer, resolveIdOpts); + return qwikPlugin.resolveId(this, id, importer, resolveIdOpts); }, load(id, loadOpts) { @@ -208,7 +210,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { if (isClientDevOnly && id === VITE_CLIENT_MODULE) { return getViteDevModule(opts); } - return qwikPlugin.load(id, loadOpts); + return qwikPlugin.load(this, id, loadOpts); }, transform(code, id) { @@ -221,7 +223,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { code = updateEntryDev(code); } } - return qwikPlugin.transform(code, id); + return qwikPlugin.transform(this, code, id); }, async generateBundle(_, rollupBundle) { @@ -439,7 +441,7 @@ export function render(document, rootNode) { qwikRender(document, rootNode); headNodes.forEach(n => document.head.appendChild(n)); - + let qwikLoader = document.getElementById('qwikloader'); if (!qwikLoader) { qwikLoader = document.createElement('script'); diff --git a/yarn.lock b/yarn.lock index 58e4161b0c0..fd667a1122f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -450,6 +450,12 @@ __metadata: languageName: node linkType: hard +"@builder.io/qwik@0.0.20-7, @builder.io/qwik@workspace:packages/qwik": + version: 0.0.0-use.local + resolution: "@builder.io/qwik@workspace:packages/qwik" + languageName: unknown + linkType: soft + "@builder.io/qwik@npm:0.0.20-5": version: 0.0.20-5 resolution: "@builder.io/qwik@npm:0.0.20-5" @@ -457,12 +463,6 @@ __metadata: languageName: node linkType: hard -"@builder.io/qwik@workspace:packages/qwik": - version: 0.0.0-use.local - resolution: "@builder.io/qwik@workspace:packages/qwik" - languageName: unknown - linkType: soft - "@cloudflare/kv-asset-handler@npm:0.2.0": version: 0.2.0 resolution: "@cloudflare/kv-asset-handler@npm:0.2.0" @@ -7627,7 +7627,7 @@ __metadata: resolution: "qwik-docs@workspace:packages/docs" dependencies: "@builder.io/partytown": ^0.5.4 - "@builder.io/qwik": 0.0.20-5 + "@builder.io/qwik": 0.0.20-7 "@builder.io/qwik-city": 0.0.5 "@cloudflare/kv-asset-handler": 0.2.0 "@cloudflare/workers-types": ^3.10.0 From af8fb26b98e79ddb19a885ad0a0568960e036af5 Mon Sep 17 00:00:00 2001 From: Manu MA Date: Mon, 23 May 2022 15:04:16 -0700 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=92=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/docs/pages/docs/file.mdx | 32 +++ .../docs/src/components/repl/worker/update.ts | 66 +++++-- packages/qwik/src/optimizer/core/src/parse.rs | 33 ++-- ...ore__test__example_capturing_fn_class.snap | 21 +- ...ore__test__example_invalid_hook_expr1.snap | 39 +++- ...ore__test__example_invalid_references.snap | 183 +++++++++++++++++- ...mple_missing_custom_inlined_functions.snap | 23 ++- packages/qwik/src/optimizer/core/src/test.rs | 6 +- .../qwik/src/optimizer/core/src/transform.rs | 27 ++- packages/qwik/src/optimizer/core/src/utils.rs | 35 ++-- packages/qwik/src/optimizer/src/api.md | 36 ++-- packages/qwik/src/optimizer/src/index.ts | 3 +- .../qwik/src/optimizer/src/plugins/rollup.ts | 12 +- .../qwik/src/optimizer/src/plugins/vite.ts | 2 +- packages/qwik/src/optimizer/src/types.ts | 32 ++- 15 files changed, 444 insertions(+), 106 deletions(-) create mode 100644 packages/docs/pages/docs/file.mdx diff --git a/packages/docs/pages/docs/file.mdx b/packages/docs/pages/docs/file.mdx new file mode 100644 index 00000000000..58e5539b2c7 --- /dev/null +++ b/packages/docs/pages/docs/file.mdx @@ -0,0 +1,32 @@ +--- +title: Overview +fetch: https://hackmd.io/@mhevery/Sy52N2Ax9 +--- + +# File + +Qwik is a new kind of web framework that can deliver instant loading web applications at any size or complexity. Your sites and apps can boot with less than 1kb of JS (_including_ your code, regardless of complexity), and achieve unheard of performance at scale. + +## Qwik is: + +- **General-purpose**: Qwik can be used to build any type of web site or application +- **Instant-on**: Unlike other frameworks, Qwik is [resumable](./concepts/resumable.mdx) which means Qwik applications require **0 hydration**. This allows Qwik apps to have instant-on interactivity, regardless of size or complexity +- **Optimized for speed**: Qwik has unprecedented performance, offering sub-second full page loads even on mobile devices. Qwik achieves this by delivering pure HTML, and incrementally loading JS only as-needed. + +Qwik Diagram + +## Does page speed really matter? + +Put simply: slow sites deter visitors, costing businesses millions. Fast sites have better SEO, better UX, and are more profitable. + +Some examples from [web.dev](https://web.dev): + +| | | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Every 100ms faster → 1% more conversions**
For Mobify, every 100ms decrease in homepage load speed worked out to a 1.11% increase in session-based conversion, yielding an average annual revenue increase of nearly $380,000. | **50% faster → 12% more sales**
When AutoAnything reduced page load time by half, they saw a boost of 12% to 13% in sales. | +| **20% faster → 10% more conversions**
Retailer Furniture Village audited their site speed and developed a plan to address the problems they found, leading to a 20% reduction in page load time and a 10% increase in conversion rate. | **40% faster → 15% more sign-ups**
Pinterest reduced perceived wait times by 40% and this increased search engine traffic and sign-ups by 15%. | +| **850ms faster → 7% more conversions**
COOK reduced average page load time by 850 milliseconds which increased conversions by 7%, decreased bounce rates by 7%, and increased pages per session by 10%. | **1 seconds slowness → 10% less users**
The BBC found they lost an additional 10% of users for every additional second their site took to load. | +| | | diff --git a/packages/docs/src/components/repl/worker/update.ts b/packages/docs/src/components/repl/worker/update.ts index e205467e0ce..9f46c427ddc 100644 --- a/packages/docs/src/components/repl/worker/update.ts +++ b/packages/docs/src/components/repl/worker/update.ts @@ -1,6 +1,6 @@ /* eslint-disable no-console */ import type { InputOptions, OutputAsset, OutputChunk } from 'rollup'; -import type { QwikRollupPluginOptions } from '@builder.io/qwik/optimizer'; +import type { Diagnostic, QwikRollupPluginOptions } from '@builder.io/qwik/optimizer'; import type { ReplInputOptions, ReplModuleOutput, ReplResult } from '../types'; import { getCtx, QwikReplContext } from './context'; import { loadDependencies } from './dependencies'; @@ -40,11 +40,13 @@ export const update = async (options: ReplInputOptions) => { ctx.clientModules = result.clientModules; } catch (e: any) { result.diagnostics.push({ + scope: 'runtime', message: String(e.stack || e), - severity: 'Error', - origin: String(e.stack || 'repl error'), - code_highlights: [], - show_environment: false, + category: 'error', + file: '', + highlights: [], + suggestions: null, + code: 'runtime error', }); console.error(e); } @@ -87,13 +89,28 @@ const bundleClient = async ( replMinify(options), ], onwarn(warning) { - result.diagnostics.push({ + const diagnostic: Diagnostic = { + scope: 'rollup-ssr', + code: warning.code ?? null, message: warning.message, - severity: 'Error', - show_environment: false, - code_highlights: [], - origin: 'client rollup', - }); + category: 'warning', + highlights: [], + file: warning.id || '', + suggestions: null, + }; + const loc = warning.loc; + if (loc && loc.file) { + diagnostic.file = loc.file; + diagnostic.highlights.push({ + startCol: loc.column, + endCol: loc.column + 1, + startLine: loc.line, + endLine: loc.line + 1, + lo: 0, + hi: 0, + }); + } + result.diagnostics.push(diagnostic); }, }; @@ -137,13 +154,28 @@ const bundleSSR = async (options: ReplInputOptions, ctx: QwikReplContext, result cache: ctx.ssrCache, plugins: [self.qwikOptimizer?.qwikRollup(qwikRollupSsrOpts), replResolver(options, 'ssr')], onwarn(warning) { - result.diagnostics.push({ + const diagnostic: Diagnostic = { + scope: 'rollup-ssr', + code: warning.code ?? null, message: warning.message, - severity: 'Error', - show_environment: false, - code_highlights: [], - origin: 'ssr rollup', - }); + category: 'warning', + highlights: [], + file: warning.id || '', + suggestions: null, + }; + const loc = warning.loc; + if (loc && loc.file) { + diagnostic.file = loc.file; + diagnostic.highlights.push({ + startCol: loc.column, + endCol: loc.column + 1, + startLine: loc.line, + endLine: loc.line + 1, + lo: 0, + hi: 0, + }); + } + result.diagnostics.push(diagnostic); }, }; diff --git a/packages/qwik/src/optimizer/core/src/parse.rs b/packages/qwik/src/optimizer/core/src/parse.rs index 416fe7c168a..313c2dc404b 100644 --- a/packages/qwik/src/optimizer/core/src/parse.rs +++ b/packages/qwik/src/optimizer/core/src/parse.rs @@ -9,7 +9,7 @@ use crate::code_move::{new_module, NewModuleCtx}; use crate::collector::global_collect; use crate::entry_strategy::EntryPolicy; use crate::transform::{HookKind, QwikTransform, QwikTransformOptions}; -use crate::utils::{CodeHighlight, Diagnostic, DiagnosticSeverity, SourceLocation}; +use crate::utils::{Diagnostic, DiagnosticCategory, DiagnosticScope, SourceLocation}; use path_slash::PathExt; use serde::{Deserialize, Serialize}; @@ -20,7 +20,7 @@ use anyhow::{Context, Error}; use swc_atoms::JsWord; use swc_common::comments::SingleThreadedComments; -use swc_common::errors::{DiagnosticBuilder, Emitter, Handler}; +use swc_common::errors::{DiagnosticBuilder, DiagnosticId, Emitter, Handler}; use swc_common::{sync::Lrc, FileName, Globals, Mark, SourceMap}; use swc_ecmascript::ast; use swc_ecmascript::codegen::text_writer::JsWriter; @@ -486,25 +486,30 @@ fn handle_error( .iter() .map(|diagnostic| { let message = diagnostic.message(); + let code = diagnostic.get_code().and_then(|m| { + if let DiagnosticId::Error(s) = m { + Some(s) + } else { + None + } + }); + let span = diagnostic.span.clone(); let suggestions = diagnostic.suggestions.clone(); let span_labels = span.span_labels(); - let code_highlights = if span_labels.is_empty() { + let highlights = if span_labels.is_empty() { None } else { Some( span_labels .into_iter() - .map(|span_label| CodeHighlight { - message: span_label.label, - loc: SourceLocation::from(source_map, span_label.span), - }) + .map(|span_label| SourceLocation::from(source_map, span_label.span)) .collect(), ) }; - let hints = if suggestions.is_empty() { + let suggestions = if suggestions.is_empty() { None } else { Some( @@ -516,13 +521,13 @@ fn handle_error( }; Diagnostic { - origin: origin.clone(), + file: origin.clone(), + code, message, - code_highlights, - hints, - show_environment: false, - severity: DiagnosticSeverity::Error, - documentation_url: None, + highlights, + suggestions, + category: DiagnosticCategory::Error, + scope: DiagnosticScope::Optimizer, } }) .collect() diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_capturing_fn_class.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_capturing_fn_class.snap index 11fe3b416ac..a6d2f89e8e5 100644 --- a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_capturing_fn_class.snap +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_capturing_fn_class.snap @@ -101,4 +101,23 @@ export { hW as handleWatch }; */ == DIAGNOSTICS == -[Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Identifier can not capture because it's a function: Thing", code_highlights: None, hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Identifier can not capture because it's a function: hola", code_highlights: None, hints: None, show_environment: false, severity: Error, documentation_url: None }] +[ + { + "category": "error", + "code": "function-reference", + "file": "test.tsx", + "message": "Identifier can not capture because it's a function: Thing", + "highlights": null, + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "function-reference", + "file": "test.tsx", + "message": "Identifier can not capture because it's a function: hola", + "highlights": null, + "suggestions": null, + "scope": "optimizer" + } +] diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_hook_expr1.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_hook_expr1.snap index 115623afb19..ac7f3f4b0ed 100644 --- a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_hook_expr1.snap +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_hook_expr1.snap @@ -123,4 +123,41 @@ export { hW as handleWatch }; */ == DIAGNOSTICS == -[Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Identifier can not be captured", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 8, start_col: 16, end_line: 8, end_col: 20 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Identifier can not be captured", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 14, start_col: 14, end_line: 14, end_col: 19 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }] +[ + { + "category": "error", + "code": "can-not-capture", + "file": "test.tsx", + "message": "Identifier can not be captured", + "highlights": [ + { + "lo": 219, + "hi": 224, + "startLine": 8, + "startCol": 16, + "endLine": 8, + "endCol": 20 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "can-not-capture", + "file": "test.tsx", + "message": "Identifier can not be captured", + "highlights": [ + { + "lo": 325, + "hi": 331, + "startLine": 14, + "startCol": 14, + "endLine": 14, + "endCol": 19 + } + ], + "suggestions": null, + "scope": "optimizer" + } +] diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_references.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_references.snap index 085c09d2478..0d8a5b67f4d 100644 --- a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_references.snap +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_invalid_references.snap @@ -94,4 +94,185 @@ export { hW as handleWatch }; */ == DIAGNOSTICS == -[Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I10", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 7, start_col: 7, end_line: 7, end_col: 9 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I1", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 4, start_col: 7, end_line: 4, end_col: 8 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I2", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 8, end_line: 5, end_col: 9 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I3", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 13, end_line: 5, end_col: 14 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I4", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 22, end_line: 5, end_col: 23 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I5", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 27, end_line: 5, end_col: 28 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I6", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 37, end_line: 5, end_col: 38 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I7", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 42, end_line: 5, end_col: 43 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I8", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 5, start_col: 52, end_line: 5, end_col: 53 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }, Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Reference to root level identifier needs to be exported: I9", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 6, start_col: 10, end_line: 6, end_col: 11 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }] +[ + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I10", + "highlights": [ + { + "lo": 153, + "hi": 156, + "startLine": 7, + "startCol": 7, + "endLine": 7, + "endCol": 9 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I1", + "highlights": [ + { + "lo": 59, + "hi": 61, + "startLine": 4, + "startCol": 7, + "endLine": 4, + "endCol": 8 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I2", + "highlights": [ + { + "lo": 75, + "hi": 77, + "startLine": 5, + "startCol": 8, + "endLine": 5, + "endCol": 9 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I3", + "highlights": [ + { + "lo": 80, + "hi": 82, + "startLine": 5, + "startCol": 13, + "endLine": 5, + "endCol": 14 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I4", + "highlights": [ + { + "lo": 89, + "hi": 91, + "startLine": 5, + "startCol": 22, + "endLine": 5, + "endCol": 23 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I5", + "highlights": [ + { + "lo": 94, + "hi": 96, + "startLine": 5, + "startCol": 27, + "endLine": 5, + "endCol": 28 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I6", + "highlights": [ + { + "lo": 104, + "hi": 106, + "startLine": 5, + "startCol": 37, + "endLine": 5, + "endCol": 38 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I7", + "highlights": [ + { + "lo": 109, + "hi": 111, + "startLine": 5, + "startCol": 42, + "endLine": 5, + "endCol": 43 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I8", + "highlights": [ + { + "lo": 119, + "hi": 121, + "startLine": 5, + "startCol": 52, + "endLine": 5, + "endCol": 53 + } + ], + "suggestions": null, + "scope": "optimizer" + }, + { + "category": "error", + "code": "root-level-reference", + "file": "test.tsx", + "message": "Reference to root level identifier needs to be exported: I9", + "highlights": [ + { + "lo": 139, + "hi": 141, + "startLine": 6, + "startCol": 10, + "endLine": 6, + "endCol": 11 + } + ], + "suggestions": null, + "scope": "optimizer" + } +] diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_missing_custom_inlined_functions.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_missing_custom_inlined_functions.snap index 38c1e810c7f..8907f9812b4 100644 --- a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_missing_custom_inlined_functions.snap +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_missing_custom_inlined_functions.snap @@ -1,5 +1,5 @@ --- -source: src/optimizer/core/src/test.rs +source: packages/qwik/src/optimizer/core/src/test.rs expression: output --- ==INPUT== @@ -44,4 +44,23 @@ export const App = component$((props)=>{ == DIAGNOSTICS == -[Diagnostic { origin: Atom('test.tsx' type=dynamic), message: "Version without $ is not exported.", code_highlights: Some([CodeHighlight { message: None, loc: SourceLocation { start_line: 11, start_col: 5, end_line: 11, end_col: 12 } }]), hints: None, show_environment: false, severity: Error, documentation_url: None }] +[ + { + "category": "error", + "code": "missing-qrl-implementation", + "file": "test.tsx", + "message": "Version without $ is not exported.", + "highlights": [ + { + "lo": 252, + "hi": 260, + "startLine": 11, + "startCol": 5, + "endLine": 11, + "endCol": 12 + } + ], + "suggestions": null, + "scope": "optimizer" + } +] diff --git a/packages/qwik/src/optimizer/core/src/test.rs b/packages/qwik/src/optimizer/core/src/test.rs index d1ae954b63c..110dfd61e2e 100644 --- a/packages/qwik/src/optimizer/core/src/test.rs +++ b/packages/qwik/src/optimizer/core/src/test.rs @@ -40,7 +40,11 @@ macro_rules! test_input { // let map = if let Some(map) = s.map { map } else { "".to_string() }; // output += format!("\n== MAP ==\n{}", map).as_str(); } - output += format!("\n== DIAGNOSTICS ==\n\n{:?}", v.diagnostics).as_str(); + output += format!( + "\n== DIAGNOSTICS ==\n\n{}", + to_string_pretty(&v.diagnostics).unwrap() + ) + .as_str(); insta::assert_display_snapshot!(output); } Err(err) => { diff --git a/packages/qwik/src/optimizer/core/src/transform.rs b/packages/qwik/src/optimizer/core/src/transform.rs index 8ddd8f8d2bf..4a05e12e04d 100644 --- a/packages/qwik/src/optimizer/core/src/transform.rs +++ b/packages/qwik/src/optimizer/core/src/transform.rs @@ -14,7 +14,7 @@ use std::hash::Hasher; use swc_atoms::JsWord; use swc_common::comments::{Comments, SingleThreadedComments}; -use swc_common::{errors::HANDLER, Mark, Span, Spanned, DUMMY_SP}; +use swc_common::{errors::DiagnosticId, errors::HANDLER, Mark, Span, Spanned, DUMMY_SP}; use swc_ecmascript::ast; use swc_ecmascript::utils::{private_ident, ExprFactory}; use swc_ecmascript::visit::{fold_expr, noop_fold_type, Fold, FoldWith, VisitWith}; @@ -329,12 +329,13 @@ impl<'a> QwikTransform<'a> { if let Some(span) = self.options.global_collect.root.get(id) { HANDLER.with(|handler| { handler - .struct_span_err( + .struct_span_err_with_code( *span, &format!( "Reference to root level identifier needs to be exported: {}", id.0 ), + DiagnosticId::Error("root-level-reference".into()), ) .emit(); }); @@ -342,10 +343,13 @@ impl<'a> QwikTransform<'a> { if invalid_decl.contains(id) { HANDLER.with(|handler| { handler - .struct_err(&format!( - "Identifier can not capture because it's a function: {}", - id.0 - )) + .struct_err_with_code( + &format!( + "Identifier can not capture because it's a function: {}", + id.0 + ), + DiagnosticId::Error("function-reference".into()), + ) .emit(); }); } @@ -356,7 +360,11 @@ impl<'a> QwikTransform<'a> { if !can_capture && !scoped_idents.is_empty() { HANDLER.with(|handler| { handler - .struct_span_err(first_arg_span, "Identifier can not be captured") + .struct_span_err_with_code( + first_arg_span, + "Identifier can not be captured", + DiagnosticId::Error("can-not-capture".into()), + ) .emit(); }); scoped_idents = vec![]; @@ -793,9 +801,12 @@ impl<'a> Fold for QwikTransform<'a> { || { HANDLER.with(|handler| { handler - .struct_span_err( + .struct_span_err_with_code( ident.span, "Version without $ is not exported.", + DiagnosticId::Error( + "missing-qrl-implementation".into(), + ), ) .emit(); }); diff --git a/packages/qwik/src/optimizer/core/src/utils.rs b/packages/qwik/src/optimizer/core/src/utils.rs index 34e61ec7533..cd8d96542c9 100644 --- a/packages/qwik/src/optimizer/core/src/utils.rs +++ b/packages/qwik/src/optimizer/core/src/utils.rs @@ -3,7 +3,10 @@ use std::cmp::Ordering; use swc_atoms::JsWord; #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct SourceLocation { + lo: usize, + hi: usize, start_line: usize, start_col: usize, end_line: usize, @@ -17,7 +20,10 @@ impl SourceLocation { // - SWC's columns are exclusive, ours are inclusive (column - 1) // - SWC has 0-based columns, ours are 1-based (column + 1) // = +-0 + Self { + lo: span.lo.0 as usize, + hi: span.hi.0 as usize, start_line: start.line, start_col: start.col_display + 1, end_line: end.line, @@ -36,24 +42,20 @@ impl PartialOrd for SourceLocation { } #[derive(Serialize, Deserialize, Debug)] -pub struct CodeHighlight { - pub message: Option, - pub loc: SourceLocation, -} - -#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] pub struct Diagnostic { - pub origin: JsWord, + pub category: DiagnosticCategory, + pub code: Option, + pub file: JsWord, pub message: String, - pub code_highlights: Option>, - pub hints: Option>, - pub show_environment: bool, - pub severity: DiagnosticSeverity, - pub documentation_url: Option, + pub highlights: Option>, + pub suggestions: Option>, + pub scope: DiagnosticScope, } #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub enum DiagnosticSeverity { +#[serde(rename_all = "camelCase")] +pub enum DiagnosticCategory { /// Fails the build with an error. Error, /// Logs a warning, but the build does not fail. @@ -62,7 +64,14 @@ pub enum DiagnosticSeverity { SourceError, } +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum DiagnosticScope { + Optimizer, +} + #[derive(Serialize, Debug, Deserialize, Eq, PartialEq, Clone, Copy)] +#[serde(rename_all = "camelCase")] pub enum SourceType { Script, Module, diff --git a/packages/qwik/src/optimizer/src/api.md b/packages/qwik/src/optimizer/src/api.md index 6ef9e316a19..155d23102da 100644 --- a/packages/qwik/src/optimizer/src/api.md +++ b/packages/qwik/src/optimizer/src/api.md @@ -4,14 +4,6 @@ ```ts -// @alpha (undocumented) -export interface CodeHighlight { - // (undocumented) - loc: SourceLocation; - // (undocumented) - message: string | null; -} - // @alpha (undocumented) export interface ComponentEntryStrategy { // (undocumented) @@ -24,23 +16,23 @@ export const createOptimizer: (optimizerOptions?: OptimizerOptions) => Promise { diagnostics.forEach((d) => { - if (d.severity === 'Error') { + if (d.category === 'error') { this.error(createRollupError(optimizer, d)); } else { this.warn(createRollupError(optimizer, d)); @@ -233,16 +233,16 @@ export function normalizeRollupOutputOptions( } export function createRollupError(optimizer: Optimizer, diagnostic: Diagnostic) { - const loc = diagnostic.code_highlights[0]?.loc ?? {}; + const loc = diagnostic.highlights[0] ?? {}; const id = optimizer - ? optimizer.sys.path.join(optimizer.sys.cwd(), diagnostic.origin) - : diagnostic.origin; + ? optimizer.sys.path.join(optimizer.sys.cwd(), diagnostic.file) + : diagnostic.file; const err: RollupError = Object.assign(new Error(diagnostic.message), { id, plugin: 'qwik', loc: { - column: loc.start_col, - line: loc.start_line, + column: loc.startCol, + line: loc.startLine, }, stack: '', }); diff --git a/packages/qwik/src/optimizer/src/plugins/vite.ts b/packages/qwik/src/optimizer/src/plugins/vite.ts index f17f96dce2d..5103fd08b90 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite.ts @@ -178,7 +178,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { qwikPlugin.onDiagnostics((diagnostics, optimizer) => { diagnostics.forEach((d) => { - if (d.severity === 'Error') { + if (d.category === 'error') { this.error(createRollupError(optimizer, d)); } else { this.warn(createRollupError(optimizer, d)); diff --git a/packages/qwik/src/optimizer/src/types.ts b/packages/qwik/src/optimizer/src/types.ts index 7b2806a541e..0d692e4730b 100644 --- a/packages/qwik/src/optimizer/src/types.ts +++ b/packages/qwik/src/optimizer/src/types.ts @@ -149,37 +149,31 @@ export interface TransformModule { * @alpha */ export interface Diagnostic { - origin: string; + scope: string; + category: DiagnosticCategory; + code: string | null; + file: string; message: string; - severity: DiagnosticType; - code_highlights: CodeHighlight[]; - documentation_url?: string; - show_environment: boolean; - hints?: string[]; -} - -/** - * @alpha - */ -export interface CodeHighlight { - message: string | null; - loc: SourceLocation; + highlights: SourceLocation[]; + suggestions: string[] | null; } /** * @alpha */ export interface SourceLocation { - start_line: number; - start_col: number; - end_line: number; - end_col: number; + hi: number; + lo: number; + startLine: number; + startCol: number; + endLine: number; + endCol: number; } /** * @alpha */ -export type DiagnosticType = 'Error' | 'Warning' | 'SourceError'; +export type DiagnosticCategory = 'error' | 'warning' | 'sourceError'; // ENTRY STRATEGY *************** From c808ffc980ece7eddbcb64e18bc2f5f9d989be55 Mon Sep 17 00:00:00 2001 From: Manu MA Date: Mon, 23 May 2022 15:12:59 -0700 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8F=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qwik/src/core/component/component-ctx.ts | 67 +++++++++---------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/packages/qwik/src/core/component/component-ctx.ts b/packages/qwik/src/core/component/component-ctx.ts index d532e5b9c51..aeba297a248 100644 --- a/packages/qwik/src/core/component/component-ctx.ts +++ b/packages/qwik/src/core/component/component-ctx.ts @@ -45,41 +45,6 @@ export const renderComponent = (rctx: RenderContext, ctx: QContext): ValueOrProm const onRenderFn = onRenderQRL.invokeFn(rctx.containerEl, invocatinContext); - function postRender() { - rctx.hostElements.add(hostElement); - const waitOnPromise = promiseAll(waitOn); - return then(waitOnPromise, (waitOnResolved) => { - waitOnResolved.forEach((task) => { - if (isStyleTask(task)) { - appendStyle(rctx, hostElement, task); - } - }); - if (ctx.dirty) { - logDebug('Dropping render. State changed during render.'); - return renderComponent(rctx, ctx); - } - let componentCtx = ctx.component; - if (!componentCtx) { - componentCtx = ctx.component = { - hostElement, - slots: [], - styleHostClass: undefined, - styleClass: undefined, - styleId: undefined, - }; - const scopedStyleId = hostElement.getAttribute(ComponentScopedStyles) ?? undefined; - if (scopedStyleId) { - componentCtx.styleId = scopedStyleId; - componentCtx.styleHostClass = styleHost(scopedStyleId); - componentCtx.styleClass = styleContent(scopedStyleId); - hostElement.classList.add(componentCtx.styleHostClass); - } - } - componentCtx.slots = []; - newCtx.components.push(componentCtx); - }); - } - try { // Execution of the render function const renderPromise = onRenderFn(wrapSubscriber(getProps(ctx), hostElement)); @@ -88,7 +53,37 @@ export const renderComponent = (rctx: RenderContext, ctx: QContext): ValueOrProm return then( renderPromise, (jsxNode) => { - return then(postRender(), () => { + rctx.hostElements.add(hostElement); + const waitOnPromise = promiseAll(waitOn); + return then(waitOnPromise, (waitOnResolved) => { + waitOnResolved.forEach((task) => { + if (isStyleTask(task)) { + appendStyle(rctx, hostElement, task); + } + }); + if (ctx.dirty) { + logDebug('Dropping render. State changed during render.'); + return renderComponent(rctx, ctx); + } + let componentCtx = ctx.component; + if (!componentCtx) { + componentCtx = ctx.component = { + hostElement, + slots: [], + styleHostClass: undefined, + styleClass: undefined, + styleId: undefined, + }; + const scopedStyleId = hostElement.getAttribute(ComponentScopedStyles) ?? undefined; + if (scopedStyleId) { + componentCtx.styleId = scopedStyleId; + componentCtx.styleHostClass = styleHost(scopedStyleId); + componentCtx.styleClass = styleContent(scopedStyleId); + hostElement.classList.add(componentCtx.styleHostClass); + } + } + componentCtx.slots = []; + newCtx.components.push(componentCtx); return visitJsxNode(newCtx, hostElement, processNode(jsxNode), false); }); },