From 9eb97681c3f56913958f1bf9d842b59b44939eee Mon Sep 17 00:00:00 2001 From: Marcos Candeia Date: Tue, 24 Sep 2024 10:44:00 -0300 Subject: [PATCH 1/5] Add transpiler Signed-off-by: Marcos Candeia --- transpile.ts | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 transpile.ts diff --git a/transpile.ts b/transpile.ts new file mode 100644 index 000000000..4a38a8bb9 --- /dev/null +++ b/transpile.ts @@ -0,0 +1,62 @@ +import { ensureDir } from "https://deno.land/std@0.224.0/fs/ensure_dir.ts"; +import { walk } from "https://deno.land/std@0.224.0/fs/walk.ts"; +import { extname, join } from "https://deno.land/std@0.224.0/path/mod.ts"; +import { build } from "https://deno.land/x/esbuild@v0.24.0/mod.js"; + +// Function to transpile TSX to JS using esbuild +async function transpileTSXToJS(inputDir: string, outputDir: string) { + for await ( + const entry of walk(inputDir, { exts: [".tsx"], includeDirs: false }) + ) { + const sourceFilePath = entry.path; + const relativePath = sourceFilePath.replace(inputDir, "."); + const outputFilePath = join( + outputDir, + relativePath.replace(`${extname(sourceFilePath)}`, ".js"), + ); + + console.log( + `Transpiling ${sourceFilePath} to ${outputFilePath} `, + ); + + // Ensure the output directory exists + console.log( + "dist", + join(outputDir, relativePath.split("/").slice(0, -1).join("/")), + ); + await ensureDir( + join( + outputDir, + relativePath.split("/").slice(0, -1).join("/"), + ), + ); + + // Use esbuild to transpile the TSX file to JS + const result = await build({ + entryPoints: [sourceFilePath], + outfile: outputFilePath, + write: true, + bundle: false, + format: "esm", + target: ["esnext"], + jsx: "preserve", // Handle JSX transformation, + loader: { ".tsx": "tsx" }, // Preserve the TypeScript syntax + jsxFactory: "React.createElement", + jsxFragment: "React.Fragment", + minify: false, + sourcemap: true, + }); + + console.log(result); + + // Clean up after esbuild + } +} + +// Set the input and output directories +const inputDir = "."; // Directory containing .tsx files + +// Transpile all TSX files +await transpileTSXToJS(inputDir, Deno.cwd()); + +console.log("Transpilation complete."); From 27a5d0fad3e21959e52e9af07849651bda70814d Mon Sep 17 00:00:00 2001 From: Marcos Candeia Date: Tue, 24 Sep 2024 11:19:40 -0300 Subject: [PATCH 2/5] Fixing transpiler Signed-off-by: Marcos Candeia --- deco.ts | 2 +- deno.json | 12 ++++++++++++ transpile.ts | 31 +++++++++++++++---------------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/deco.ts b/deco.ts index 3bb1c89a1..c7a56ad2e 100644 --- a/deco.ts +++ b/deco.ts @@ -1,6 +1,6 @@ import "./utils/patched_fetch.ts"; -import { AsyncLocalStorage } from "node:async_hooks"; +//import { AsyncLocalStorage } from "node:async_hooks"; import type { ImportMap } from "./blocks/app.ts"; import type { ReleaseResolver } from "./engine/core/mod.ts"; import type { DecofileProvider } from "./engine/decofile/provider.ts"; diff --git a/deno.json b/deno.json index 8f8607b4d..19db8ca9c 100644 --- a/deno.json +++ b/deno.json @@ -61,25 +61,36 @@ } }, "imports": { + "@deco/deco": "./mod.ts", + "@deco/deco/hooks": "./hooks/mod.ts", + "@deco/deco/htmx": "./runtime/htmx/mod.ts", "$fresh/": "https://denopkg.com/denoland/fresh@1.6.8/", "@cliffy/prompt": "jsr:@cliffy/prompt@^1.0.0-rc.5", "@core/asyncutil": "jsr:@core/asyncutil@^1.0.2", + "@core/asyncutil/": "jsr:/@core/asyncutil@^1.0.2/", "@deco/codemod-toolkit": "jsr:@deco/codemod-toolkit@^0.3.1", "@deco/durable": "jsr:@deco/durable@^0.5.3", "@deco/warp": "jsr:@deco/warp@^0.3.8", "@hono/hono": "jsr:@hono/hono@^4.5.4", + "@hono/hono/": "jsr:/@hono/hono@^4.5.4/", "@std/assert": "jsr:@std/assert@^1.0.2", "@std/async": "jsr:@std/async@^0.224.1", + "@std/async/": "jsr:/@std/async@^0.224.1/", "@std/cli": "jsr:@std/cli@^1.0.3", "@std/crypto": "jsr:@std/crypto@1.0.0-rc.1", "@std/datetime": "jsr:@std/datetime@^0.224.0", "@std/encoding": "jsr:@std/encoding@^1.0.0-rc.1", "@std/flags": "jsr:@std/flags@^0.224.0", "@std/fmt": "jsr:@std/fmt@^0.225.3", + "@std/fmt/": "jsr:/@std/fmt@^0.225.3/", "@std/fs": "jsr:@std/fs@^0.229.1", + "@std/fs/": "jsr:/@std/fs@^0.229.1/", "@std/http": "jsr:@std/http@^1.0.0", + "@std/http/": "jsr:/@std/http@^1.0.0/", "@std/io": "jsr:@std/io@^0.224.4", + "@std/io/": "jsr:/@std/io@^0.224.4/", "@std/log": "jsr:@std/log@^0.224.5", + "@std/log/": "jsr:/@std/log@^0.224.5/", "@std/media-types": "jsr:@std/media-types@^1.0.0-rc.1", "@std/path": "jsr:@std/path@^0.225.2", "@std/semver": "jsr:@std/semver@^0.224.3", @@ -89,6 +100,7 @@ "fast-json-patch": "npm:fast-json-patch@^3.1.1", "partytown/": "https://deno.land/x/partytown@0.3.0/", "preact": "npm:preact@10.23.1", + "preact/": "npm:/preact@10.23.1/", "preact-render-to-string": "npm:preact-render-to-string@6.4.0", "simple-git": "npm:simple-git@^3.25.0", "std/": "https://deno.land/std@0.203.0/" diff --git a/transpile.ts b/transpile.ts index 4a38a8bb9..8e35189da 100644 --- a/transpile.ts +++ b/transpile.ts @@ -1,7 +1,7 @@ import { ensureDir } from "https://deno.land/std@0.224.0/fs/ensure_dir.ts"; import { walk } from "https://deno.land/std@0.224.0/fs/walk.ts"; import { extname, join } from "https://deno.land/std@0.224.0/path/mod.ts"; -import { build } from "https://deno.land/x/esbuild@v0.24.0/mod.js"; +import { transpile } from "jsr:@deno/emit"; // Function to transpile TSX to JS using esbuild async function transpileTSXToJS(inputDir: string, outputDir: string) { @@ -31,23 +31,22 @@ async function transpileTSXToJS(inputDir: string, outputDir: string) { ), ); - // Use esbuild to transpile the TSX file to JS - const result = await build({ - entryPoints: [sourceFilePath], - outfile: outputFilePath, - write: true, - bundle: false, - format: "esm", - target: ["esnext"], - jsx: "preserve", // Handle JSX transformation, - loader: { ".tsx": "tsx" }, // Preserve the TypeScript syntax - jsxFactory: "React.createElement", - jsxFragment: "React.Fragment", - minify: false, - sourcemap: true, + const url = new URL(sourceFilePath, import.meta.url); + console.log(`file://${join(Deno.cwd(), "deno.json")}`); + + const result = await transpile(url, { + allowRemote: true, + compilerOptions: { + "jsx": "react-jsx", + "jsxImportSource": "preact", + }, + importMap: join(Deno.cwd(), "deno.json"), }); - console.log(result); + const code = result.get(url.href); + + const tsFile = url.href.replace(".tsx", ".ts"); + code && await Deno.writeTextFile(tsFile, code) // Clean up after esbuild } From 3868f2443bd88eca817a0ed75bd3371e030a1a24 Mon Sep 17 00:00:00 2001 From: Marcos Candeia Date: Tue, 24 Sep 2024 11:35:59 -0300 Subject: [PATCH 3/5] Start transpiling files Signed-off-by: Marcos Candeia --- blocks/action.ts | 2 +- blocks/app.ts | 12 +- blocks/appsUtil.ts | 2 +- blocks/function.ts | 2 +- blocks/handler.ts | 2 +- blocks/index.ts | 2 +- blocks/loader.ts | 2 +- blocks/matcher.ts | 2 +- blocks/mod.ts | 14 +-- blocks/{page.tsx => page.ts} | 9 +- blocks/propsLoader.ts | 2 +- blocks/section.ts | 8 +- blocks/{utils.tsx => utils.ts} | 9 +- blocks/workflow.ts | 8 +- components/section.tsx | 4 +- engine/manifest/manifest.ts | 2 +- .../workspace/deco/blocks/utils.ts | 105 ++++++++++++++++++ runtime/deps.ts | 2 +- runtime/features/preview.tsx | 2 +- runtime/features/render.tsx | 2 +- runtime/htmx/{mod.tsx => framework.ts} | 42 ++++--- runtime/htmx/mod.ts | 3 +- runtime/mod.ts | 5 +- runtime/routes/blockPreview.tsx | 2 +- runtime/routes/entrypoint.tsx | 2 +- runtime/routes/previews.tsx | 2 +- runtime/utils.ts | 4 +- transpile.ts | 85 +++++++------- types.ts | 8 +- utils/segment.ts | 2 +- 30 files changed, 232 insertions(+), 116 deletions(-) rename blocks/{page.tsx => page.ts} (89%) rename blocks/{utils.tsx => utils.ts} (97%) create mode 100644 file:/Users/marcoscandeia/workspace/deco/blocks/utils.ts rename runtime/htmx/{mod.tsx => framework.ts} (81%) diff --git a/blocks/action.ts b/blocks/action.ts index beb03db2d..6f940fe2c 100644 --- a/blocks/action.ts +++ b/blocks/action.ts @@ -1,7 +1,7 @@ // deno-lint-ignore-file no-explicit-any -import { applyProps, type FnProps } from "../blocks/utils.tsx"; import JsonViewer from "../components/JsonViewer.tsx"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; +import { applyProps, type FnProps } from "./utils.ts"; export type Action = InstanceOf; diff --git a/blocks/app.ts b/blocks/app.ts index 6a3e7f7fd..e6deb74d6 100644 --- a/blocks/app.ts +++ b/blocks/app.ts @@ -2,11 +2,6 @@ import blocks from "../blocks/index.ts"; import { propsLoader } from "../blocks/propsLoader.ts"; import type { SectionModule } from "../blocks/section.ts"; -import { - type AppHttpContext, - buildImportMap, - type FnProps, -} from "../blocks/utils.tsx"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; import type { BaseContext, @@ -23,7 +18,12 @@ import type { import type { DecoManifest, FnContext } from "../types.ts"; import { resolversFrom } from "./appsUtil.ts"; import { isInvokeCtx } from "./loader.ts"; -import { fnContextFromHttpContext } from "./utils.tsx"; +import { + type AppHttpContext, + buildImportMap, + fnContextFromHttpContext, + type FnProps, +} from "./utils.ts"; export type Apps = InstanceOf; export type AppManifest = Omit; diff --git a/blocks/appsUtil.ts b/blocks/appsUtil.ts index db73d103f..44c2ab004 100644 --- a/blocks/appsUtil.ts +++ b/blocks/appsUtil.ts @@ -13,7 +13,7 @@ import { import type { DanglingRecover } from "../engine/manifest/manifest.ts"; import { compose, type ResolverMiddleware } from "../engine/middleware.ts"; import type { AppManifest } from "../types.ts"; -import { usePreviewFunc } from "./utils.tsx"; +import { usePreviewFunc } from "./utils.ts"; const resolverIsBlock = (blk: Block) => (resolver: string) => { const splitted = resolver.split("/"); diff --git a/blocks/function.ts b/blocks/function.ts index 888845f2f..c451e97d3 100644 --- a/blocks/function.ts +++ b/blocks/function.ts @@ -4,7 +4,7 @@ import { wrapCaughtErrors } from "../blocks/loader.ts"; import { newSingleFlightGroup, type SingleFlightKeyFunc, -} from "../blocks/utils.tsx"; +} from "../blocks/utils.ts"; import JsonViewer from "../components/JsonViewer.tsx"; import type { Block, BlockModule } from "../engine/block.ts"; import type { HandlerContext } from "../engine/manifest/manifest.ts"; diff --git a/blocks/handler.ts b/blocks/handler.ts index c34625037..27f521951 100644 --- a/blocks/handler.ts +++ b/blocks/handler.ts @@ -8,7 +8,7 @@ import { type FnContext, fnContextFromHttpContext, type RequestState, -} from "./utils.tsx"; +} from "./utils.ts"; export interface HttpContext< // deno-lint-ignore ban-types diff --git a/blocks/index.ts b/blocks/index.ts index 0476350c5..b60573c58 100644 --- a/blocks/index.ts +++ b/blocks/index.ts @@ -9,7 +9,7 @@ import matcherBlock from "../blocks/matcher.ts"; import sectionBlock from "../blocks/section.ts"; import workflowBlock from "../blocks/workflow.ts"; import type { Block } from "../engine/block.ts"; -import pageBlock from "./page.tsx"; +import pageBlock from "./page.ts"; const userDefinedBlocks: Block[] = []; diff --git a/blocks/loader.ts b/blocks/loader.ts index 1fb2272c1..09b922e1d 100644 --- a/blocks/loader.ts +++ b/blocks/loader.ts @@ -18,7 +18,7 @@ import { type FnProps, type RequestState, type SingleFlightKeyFunc, -} from "./utils.tsx"; +} from "./utils.ts"; export type Loader = InstanceOf; diff --git a/blocks/matcher.ts b/blocks/matcher.ts index 315dc1e52..b8148ad1c 100644 --- a/blocks/matcher.ts +++ b/blocks/matcher.ts @@ -2,7 +2,7 @@ import type { HttpContext } from "../blocks/handler.ts"; import { getCookies, Murmurhash3, setCookie } from "../deps.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; import type { Device } from "../utils/userAgent.ts"; -import type { RequestState } from "./utils.tsx"; +import type { RequestState } from "./utils.ts"; export type Matcher = InstanceOf; diff --git a/blocks/mod.ts b/blocks/mod.ts index 58149a577..19a530f2a 100644 --- a/blocks/mod.ts +++ b/blocks/mod.ts @@ -1,7 +1,6 @@ export type { WorkflowGen } from "@deco/durable"; export { - type SectionContext, - SectionContext as SectionCtx, + SectionContext as SectionCtx, type SectionContext } from "../components/section.tsx"; export type { ComponentFunc, ComponentMetadata } from "../engine/block.ts"; export type { Resolvable } from "../engine/core/resolver.ts"; @@ -12,21 +11,22 @@ export type { AppMiddlewareContext, Apps, ImportMap, - ManifestOf, + ManifestOf } from "./app.ts"; export type { Flag, FlagObj, MultivariateFlag, Variant } from "./flag.ts"; export type { Handler } from "./handler.ts"; export { default as blocks, defineBlock } from "./index.ts"; export type { Loader } from "./loader.ts"; export type { MatchContext, Matcher } from "./matcher.ts"; -export type { Page } from "./page.tsx"; +export type { Page } from "./page.ts"; export { isSection, type Section } from "./section.ts"; export { applyProps, buildImportMap, buildImportMapWith, - createBagKey, -} from "./utils.tsx"; -export type { FnProps } from "./utils.tsx"; + createBagKey +} from "./utils.ts"; +export type { FnProps } from "./utils.ts"; export { WorkflowContext } from "./workflow.ts"; export type { Workflow, WorkflowFn } from "./workflow.ts"; + diff --git a/blocks/page.tsx b/blocks/page.ts similarity index 89% rename from blocks/page.tsx rename to blocks/page.ts index 41c33d009..b674ea4ea 100644 --- a/blocks/page.tsx +++ b/blocks/page.ts @@ -1,7 +1,5 @@ // deno-lint-ignore-file no-explicit-any -/** @jsxRuntime automatic */ -/** @jsxImportSource preact */ - +import { jsx as _jsx } from "preact/jsx-runtime"; import type { Block, InstanceOf, ResolverLike } from "../engine/block.ts"; import { createSectionBlock, type SectionModule } from "./section.ts"; @@ -27,7 +25,10 @@ const page: Block< any > = createSectionBlock( (component, ComponentFunc) => (props, { resolveChain }) => ({ - Component: (p) => , + Component: (p) => + /*#__PURE__*/ _jsx(ComponentFunc, { + ...p, + }), props, metadata: { resolveChain, component }, }), diff --git a/blocks/propsLoader.ts b/blocks/propsLoader.ts index e98105712..4fe528c52 100644 --- a/blocks/propsLoader.ts +++ b/blocks/propsLoader.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-explicit-any -import type { FnProps } from "../blocks/utils.tsx"; +import type { FnProps } from "../blocks/utils.ts"; import type { Diff, Intersection, diff --git a/blocks/section.ts b/blocks/section.ts index 7f655e78c..8ae39d333 100644 --- a/blocks/section.ts +++ b/blocks/section.ts @@ -3,10 +3,6 @@ import type { ComponentType, JSX } from "preact"; import type { AppManifest } from "../blocks/app.ts"; import type { HttpContext } from "../blocks/handler.ts"; import { type PropsLoader, propsLoader } from "../blocks/propsLoader.ts"; -import { - fnContextFromHttpContext, - type RequestState, -} from "../blocks/utils.tsx"; import StubSection, { Empty } from "../components/StubSection.tsx"; import { alwaysThrow, withSection } from "../components/section.tsx"; import { Context } from "../deco.ts"; @@ -20,6 +16,10 @@ import type { } from "../engine/block.ts"; import type { Resolver } from "../engine/core/resolver.ts"; import { HttpError } from "../engine/errors.ts"; +import { + fnContextFromHttpContext, + type RequestState, +} from "./utils.ts"; /** * @widget none diff --git a/blocks/utils.tsx b/blocks/utils.ts similarity index 97% rename from blocks/utils.tsx rename to blocks/utils.ts index 89e8c2ade..7ededd3ff 100644 --- a/blocks/utils.tsx +++ b/blocks/utils.ts @@ -1,11 +1,6 @@ -/** @jsxRuntime automatic */ -/** @jsxImportSource preact */ - // deno-lint-ignore-file no-explicit-any import type { StatusCode as Status } from "@std/http/status"; import type { JSX } from "preact"; -import type { AppManifest, ImportMap } from "../blocks/app.ts"; -import { isInvokeCtx } from "../blocks/loader.ts"; import type { InvocationFunc } from "../clients/withManifest.ts"; import { withSection } from "../components/section.tsx"; import type { @@ -25,8 +20,10 @@ import type { Flag } from "../types.ts"; import { buildInvokeFunc } from "../utils/invoke.server.ts"; import type { InvocationProxy } from "../utils/invoke.types.ts"; import { type Device, deviceOf, isBot as isUABot } from "../utils/userAgent.ts"; -import type { HttpContext } from "./handler.ts"; import type { Vary } from "../utils/vary.ts"; +import type { AppManifest, ImportMap } from "./app.ts"; +import type { HttpContext } from "./handler.ts"; +import { isInvokeCtx } from "./loader.ts"; export type SingleFlightKeyFunc = ( args: TConfig, diff --git a/blocks/workflow.ts b/blocks/workflow.ts index c8d3f36b6..d5db3ff0c 100644 --- a/blocks/workflow.ts +++ b/blocks/workflow.ts @@ -1,13 +1,14 @@ // deno-lint-ignore-file no-explicit-any import { type Arg, - type LocalActivityCommand, - type Metadata, type Workflow as DurableWorkflow, WorkflowContext as DurableWorkflowContext, + type LocalActivityCommand, + type Metadata, type WorkflowExecution, } from "../deps.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; +import type { AppManifest, DecoSiteState, DecoState } from "../types.ts"; import type { AvailableActions, AvailableFunctions, @@ -18,14 +19,13 @@ import type { ManifestFunction, ManifestLoader, } from "../utils/invoke.types.ts"; -import type { AppManifest, DecoSiteState, DecoState } from "../types.ts"; import type { DotNestedKeys } from "../utils/object.ts"; import type { HttpContext } from "./handler.ts"; import { type FnContext, fnContextFromHttpContext, type RequestState, -} from "./utils.tsx"; +} from "./utils.ts"; export interface WorkflowMetadata extends Metadata { defaultInvokeHeaders?: Record; diff --git a/components/section.tsx b/components/section.tsx index 1614bb8f2..c259bbda8 100644 --- a/components/section.tsx +++ b/components/section.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ -import type { Context as PreactContext, JSX } from "preact"; +import type { JSX, Context as PreactContext } from "preact"; import { Component, type ComponentChildren, @@ -10,7 +10,7 @@ import { } from "preact"; import { useContext } from "preact/hooks"; import type { HttpContext } from "../blocks/handler.ts"; -import type { RequestState } from "../blocks/utils.tsx"; +import type { RequestState } from "../blocks/utils.ts"; import { Context } from "../deco.ts"; import { type DeepPartial, Murmurhash3 } from "../deps.ts"; import type { ComponentFunc, ComponentMetadata } from "../engine/block.ts"; diff --git a/engine/manifest/manifest.ts b/engine/manifest/manifest.ts index 4dfd3558f..30be010df 100644 --- a/engine/manifest/manifest.ts +++ b/engine/manifest/manifest.ts @@ -10,7 +10,7 @@ import { } from "../../blocks/app.ts"; import { buildRuntime } from "../../blocks/appsUtil.ts"; import blocks from "../../blocks/index.ts"; -import { buildImportMap } from "../../blocks/utils.tsx"; +import { buildImportMap } from "../../blocks/utils.ts"; import { Context, context, diff --git a/file:/Users/marcoscandeia/workspace/deco/blocks/utils.ts b/file:/Users/marcoscandeia/workspace/deco/blocks/utils.ts new file mode 100644 index 000000000..e078e6c7c --- /dev/null +++ b/file:/Users/marcoscandeia/workspace/deco/blocks/utils.ts @@ -0,0 +1,105 @@ +/** @jsxRuntime automatic */ /** @jsxImportSource preact */ // deno-lint-ignore-file no-explicit-any +import { isInvokeCtx } from "../blocks/loader.ts"; +import { withSection } from "../components/section.tsx"; +import { singleFlight } from "../engine/core/utils.ts"; +import { buildInvokeFunc } from "../utils/invoke.server.ts"; +import { deviceOf, isBot as isUABot } from "../utils/userAgent.ts"; +export const applyConfig = (func)=>async ($live)=>{ + return await func.default($live); + }; +export const applyConfigFunc = (func)=>async ($live)=>{ + const resp = await func.default($live); + return typeof resp === "function" ? resp : ()=>resp; + }; +/** + * Creates a unique bag key for the given description + * @param description the description of the key + * @returns a symbol that can be used as a bag key + */ export const createBagKey = (description)=>Symbol(description); +// deno-lint-ignore ban-types +export const fnContextFromHttpContext = (ctx)=>{ + let device = null; + let isBot = null; + return { + ...ctx?.context?.state?.global, + revision: ctx.revision, + resolverId: ctx.resolverId, + monitoring: ctx.monitoring, + get: ctx.resolve, + response: ctx.context.state.response, + bag: ctx.context.state.bag, + isInvoke: isInvokeCtx(ctx), + invoke: buildInvokeFunc(ctx.resolve, { + propagateOptions: true + }, { + isInvoke: true, + resolveChain: ctx.resolveChain + }), + get device () { + return device ??= deviceOf(ctx.request); + }, + get isBot () { + return isBot ??= isUABot(ctx.request); + } + }; +}; +/** + * Applies the given props to the target block function. + * + * @template TProps, TResp + * @param {Object} func - A function with a `default` property. + * @param {TProps} $live - Props to be applied to the function. + * @param {HttpContext<{ global: any } & RequestState>} ctx - A context object containing global state and request information. + * @returns {PromiseOrValue} The result of the function call with the applied props. + */ export const applyProps = (func)=>($live, ctx)=>{ + return func.default($live, ctx.request, fnContextFromHttpContext(ctx)); + }; +export const fromComponentFunc = ({ default: Component }, component)=>withSection(component, Component); +const isPreactComponent = (v)=>{ + return typeof v.Component === "function"; +}; +export const usePreviewFunc = (Component)=>(component)=>{ + return { + ...isPreactComponent(component) ? component : { + props: component + }, + Component + }; + }; +export const newComponentBlock = (type, defaultDanglingRecover)=>({ + type, + defaultDanglingRecover, + defaultPreview: (comp)=>comp, + adapt: fromComponentFunc + }); +export const newSingleFlightGroup = (singleFlightKeyFunc)=>{ + const flights = singleFlight(); + return (c, ctx)=>{ + if (!singleFlightKeyFunc) { + return ctx.next(); + } + return flights.do(`${singleFlightKeyFunc(c, ctx)}`, ()=>ctx.next()); + }; +}; +export const buildImportMapWith = (manifest, importMapBuilder)=>{ + const importMap = { + imports: {} + }; + const { baseUrl: _ignoreBaseUrl, name: _ignoreName, ...appManifest } = manifest; + for (const value of Object.values(appManifest)){ + for (const blockKey of Object.keys(value)){ + importMap.imports[blockKey] = importMapBuilder(blockKey); + } + } + return importMap; +}; +export const buildImportMap = (manifest)=>{ + const { baseUrl, name } = manifest; + if (!URL.canParse("./", baseUrl)) { + return { + imports: {} + }; + } + const builder = (blockKey)=>blockKey.replace(`${name}/`, new URL("./", baseUrl).href); + return buildImportMapWith(manifest, builder); +}; diff --git a/runtime/deps.ts b/runtime/deps.ts index 2c743fbb0..6d458f3a9 100644 --- a/runtime/deps.ts +++ b/runtime/deps.ts @@ -1,4 +1,4 @@ -import type { Page } from "../blocks/page.tsx"; +import type { Page } from "../blocks/page.ts"; export { Hono } from "@hono/hono"; export type { Context, Handler, Input, MiddlewareHandler } from "@hono/hono"; diff --git a/runtime/features/preview.tsx b/runtime/features/preview.tsx index b0307e12c..439426364 100644 --- a/runtime/features/preview.tsx +++ b/runtime/features/preview.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ -import type { Page } from "../../blocks/page.tsx"; +import type { Page } from "../../blocks/page.ts"; import type { AppManifest } from "../../types.ts"; import type { State } from "../mod.ts"; diff --git a/runtime/features/render.tsx b/runtime/features/render.tsx index c7de65a76..8a42f8831 100644 --- a/runtime/features/render.tsx +++ b/runtime/features/render.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ -import type { Page } from "../../blocks/page.tsx"; +import type { Page } from "../../blocks/page.ts"; import { getSectionID } from "../../components/section.tsx"; import type { FieldResolver, Resolvable } from "../../engine/core/resolver.ts"; import { HttpError } from "../../engine/errors.ts"; diff --git a/runtime/htmx/mod.tsx b/runtime/htmx/framework.ts similarity index 81% rename from runtime/htmx/mod.tsx rename to runtime/htmx/framework.ts index 27ac12d7d..cb604c369 100644 --- a/runtime/htmx/mod.tsx +++ b/runtime/htmx/framework.ts @@ -1,7 +1,11 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ - import type { ComponentChildren, ComponentType } from "preact"; +import { + Fragment as _Fragment, + jsx as _jsx, + jsxs as _jsxs, +} from "preact/jsx-runtime"; import { Context } from "../../deco.ts"; import type { AppManifest } from "../../types.ts"; import { Hono, upgradeWebSocket } from "../deps.ts"; @@ -11,10 +15,9 @@ import framework from "./Bindings.tsx"; import { renderFn } from "./Renderer.tsx"; import { staticFiles } from "./serveStatic.ts"; const DEV_SERVER_PATH = `/deco/dev`; -const DEV_SERVER_SCRIPT = ( - -); + }, +}); let hmrUniqueId = crypto.randomUUID(); const sockets = new Map(); @@ -101,7 +102,11 @@ export const HTMX = < }), ); hono.use(staticFiles(opts?.staticRoot)); - const Layout = opts?.Layout ?? (({ children }) => <>{children}); + const Layout = opts?.Layout ?? + (({ children }) => + /*#__PURE__*/ _jsx(_Fragment, { + children: children, + })); return { server: hono, framework, @@ -113,12 +118,17 @@ export const HTMX = < page: { metadata: page.metadata, Component: () => { - return ( - - {!active.isDeploy ? DEV_SERVER_SCRIPT : null} - - - ); + // @ts-expect-error: i dont know why this is happening + return /*#__PURE__*/ _jsxs(Layout, { + hmrUniqueId: hmrUniqueId, + revision: revision, + children: [ + !active.isDeploy ? DEV_SERVER_SCRIPT : null, + /*#__PURE__*/ _jsx(page.Component, { + ...page.props, + }), + ], + }); }, props: {}, }, diff --git a/runtime/htmx/mod.ts b/runtime/htmx/mod.ts index 01bbae9d5..e148fdf09 100644 --- a/runtime/htmx/mod.ts +++ b/runtime/htmx/mod.ts @@ -1,4 +1,5 @@ export { default as framework } from "./Bindings.tsx"; -export { HTMX as bindings } from "./mod.tsx"; +export { HTMX as bindings } from "./framework.ts"; export { Head } from "./Renderer.tsx"; export { asset } from "./serveStatic.ts"; + diff --git a/runtime/mod.ts b/runtime/mod.ts index 163928998..cdc827154 100644 --- a/runtime/mod.ts +++ b/runtime/mod.ts @@ -1,7 +1,6 @@ // deno-lint-ignore-file no-explicit-any import { join, toFileUrl } from "@std/path"; -import type { RequestState } from "../blocks/utils.tsx"; -import { vary } from "../utils/vary.ts"; +import type { RequestState } from "../blocks/utils.ts"; import type { DecoContext } from "../deco.ts"; import { Context } from "../deco.ts"; import { context as otelContext } from "../deps.ts"; @@ -23,6 +22,7 @@ import type { AppManifest, DecoSiteState, DecoState } from "../types.ts"; import { defaultHeaders, forceHttps } from "../utils/http.ts"; import { buildInvokeFunc } from "../utils/invoke.server.ts"; import { createServerTimings } from "../utils/timings.ts"; +import { vary } from "../utils/vary.ts"; import type { ContextRenderer } from "./deps.ts"; import { batchInvoke, invoke } from "./features/invoke.ts"; import { @@ -266,3 +266,4 @@ export class Deco { export type { PageData } from "./deps.ts"; export { DECO_SEGMENT } from "./middleware.ts"; export { usePageContext, useRouterContext } from "./routes/entrypoint.tsx"; + diff --git a/runtime/routes/blockPreview.tsx b/runtime/routes/blockPreview.tsx index eb6187b29..a40831c65 100644 --- a/runtime/routes/blockPreview.tsx +++ b/runtime/routes/blockPreview.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ -import type { Page } from "../../blocks/page.tsx"; +import type { Page } from "../../blocks/page.ts"; import { bodyFromUrl } from "../../utils/http.ts"; import { createHandler, type DecoMiddlewareContext } from "../middleware.ts"; import type { PageParams } from "../mod.ts"; diff --git a/runtime/routes/entrypoint.tsx b/runtime/routes/entrypoint.tsx index b2ecee92e..c64f82767 100644 --- a/runtime/routes/entrypoint.tsx +++ b/runtime/routes/entrypoint.tsx @@ -4,7 +4,7 @@ import { createContext } from "preact"; import { useContext } from "preact/hooks"; import type { Handler } from "../../blocks/handler.ts"; -import type { Page } from "../../blocks/page.tsx"; +import type { Page } from "../../blocks/page.ts"; import type { PageContext } from "../../engine/block.ts"; import type { Flag } from "../../types.ts"; import { forceHttps, setCSPHeaders } from "../../utils/http.ts"; diff --git a/runtime/routes/previews.tsx b/runtime/routes/previews.tsx index 10981fd98..c7b67d274 100644 --- a/runtime/routes/previews.tsx +++ b/runtime/routes/previews.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime automatic */ /** @jsxImportSource preact */ -import type { Page } from "../../blocks/page.tsx"; +import type { Page } from "../../blocks/page.ts"; import LiveControls from "../../components/LiveControls.tsx"; import { Context } from "../../deco.ts"; import type { ComponentMetadata } from "../../engine/block.ts"; diff --git a/runtime/utils.ts b/runtime/utils.ts index fb23f01d6..5e748ddd7 100644 --- a/runtime/utils.ts +++ b/runtime/utils.ts @@ -1,7 +1,7 @@ -import type { RequestState } from "../blocks/utils.tsx"; -import { vary } from "../utils/vary.ts"; +import type { RequestState } from "../blocks/utils.ts"; import { Context } from "../deco.ts"; import { defaultHeaders } from "../utils/http.ts"; +import { vary } from "../utils/vary.ts"; export const sha1 = async (text: string) => { const buffer = await crypto.subtle diff --git a/transpile.ts b/transpile.ts index 8e35189da..3f2d8f1ae 100644 --- a/transpile.ts +++ b/transpile.ts @@ -3,52 +3,52 @@ import { walk } from "https://deno.land/std@0.224.0/fs/walk.ts"; import { extname, join } from "https://deno.land/std@0.224.0/path/mod.ts"; import { transpile } from "jsr:@deno/emit"; +const transpileEntry = async (entry: { path: string }, outputDir: string) => { + const sourceFilePath = entry.path; + const relativePath = sourceFilePath.replace(inputDir, "."); + const outputFilePath = join( + outputDir, + relativePath.replace(`${extname(sourceFilePath)}`, ".js"), + ); + + console.log( + `Transpiling ${sourceFilePath} to ${outputFilePath} `, + ); + + // Ensure the output directory exists + console.log( + "dist", + join(outputDir, relativePath.split("/").slice(0, -1).join("/")), + ); + await ensureDir( + join( + outputDir, + relativePath.split("/").slice(0, -1).join("/"), + ), + ); + + const url = new URL(sourceFilePath, import.meta.url); + console.log(`file://${join(Deno.cwd(), "deno.json")}`); + + const result = await transpile(url, { + allowRemote: true, + compilerOptions: { + "jsx": "react-jsx", + "jsxImportSource": "preact", + }, + importMap: join(Deno.cwd(), "deno.json"), + }); + + const code = result.get(url.href); + + console.log(code); +}; // Function to transpile TSX to JS using esbuild async function transpileTSXToJS(inputDir: string, outputDir: string) { for await ( const entry of walk(inputDir, { exts: [".tsx"], includeDirs: false }) ) { - const sourceFilePath = entry.path; - const relativePath = sourceFilePath.replace(inputDir, "."); - const outputFilePath = join( - outputDir, - relativePath.replace(`${extname(sourceFilePath)}`, ".js"), - ); - - console.log( - `Transpiling ${sourceFilePath} to ${outputFilePath} `, - ); - - // Ensure the output directory exists - console.log( - "dist", - join(outputDir, relativePath.split("/").slice(0, -1).join("/")), - ); - await ensureDir( - join( - outputDir, - relativePath.split("/").slice(0, -1).join("/"), - ), - ); - - const url = new URL(sourceFilePath, import.meta.url); - console.log(`file://${join(Deno.cwd(), "deno.json")}`); - - const result = await transpile(url, { - allowRemote: true, - compilerOptions: { - "jsx": "react-jsx", - "jsxImportSource": "preact", - }, - importMap: join(Deno.cwd(), "deno.json"), - }); - - const code = result.get(url.href); - - const tsFile = url.href.replace(".tsx", ".ts"); - code && await Deno.writeTextFile(tsFile, code) - - // Clean up after esbuild + transpileEntry(entry, outputDir); } } @@ -56,6 +56,7 @@ async function transpileTSXToJS(inputDir: string, outputDir: string) { const inputDir = "."; // Directory containing .tsx files // Transpile all TSX files -await transpileTSXToJS(inputDir, Deno.cwd()); +// await transpileTSXToJS(inputDir, Deno.cwd()); +await transpileEntry({ path: Deno.args[0]! }, Deno.cwd()); console.log("Transpilation complete."); diff --git a/types.ts b/types.ts index 225dd6db7..7875bbc03 100644 --- a/types.ts +++ b/types.ts @@ -14,9 +14,9 @@ import type handlerBlock from "./blocks/handler.ts"; import type { Handler } from "./blocks/handler.ts"; import type loaderBlock from "./blocks/loader.ts"; import type matcherBlock from "./blocks/matcher.ts"; -import type pageBlock from "./blocks/page.tsx"; +import type pageBlock from "./blocks/page.ts"; import type sectionBlock from "./blocks/section.ts"; -import type { FnContext } from "./blocks/utils.tsx"; +import type { FnContext } from "./blocks/utils.ts"; import type workflowBlock from "./blocks/workflow.ts"; import type { InvocationFunc } from "./clients/withManifest.ts"; import type { JSONSchema7, JSONSchema7Definition } from "./deps.ts"; @@ -35,7 +35,7 @@ import type { createServerTimings } from "./utils/timings.ts"; export type { App } from "./blocks/app.ts"; export type { ErrorBoundaryComponent, - ErrorBoundaryParams, + ErrorBoundaryParams } from "./blocks/section.ts"; export type { AppContext, AppManifest, AppModule, AppRuntime }; export type JSONSchema = JSONSchema7; @@ -134,7 +134,7 @@ export type DecoState< export type { JSONSchema7 } from "npm:@types/json-schema@7.0.11/index.d.ts"; export type { PropsLoader } from "./blocks/propsLoader.ts"; export type { LoadingFallbackProps, SectionProps } from "./blocks/section.ts"; -export type { FnContext } from "./blocks/utils.tsx"; +export type { FnContext } from "./blocks/utils.ts"; export type { ResolveOptions } from "./engine/core/mod.ts"; export type { ResolveFunc } from "./engine/core/resolver.ts"; export type { RouteContext } from "./engine/manifest/manifest.ts"; diff --git a/utils/segment.ts b/utils/segment.ts index 025b90ec9..7844e4335 100644 --- a/utils/segment.ts +++ b/utils/segment.ts @@ -1,6 +1,6 @@ import { getSetCookies } from "@std/http/cookie"; import { DECO_MATCHER_PREFIX } from "../blocks/matcher.ts"; -import type { RequestState } from "../blocks/utils.tsx"; +import type { RequestState } from "../blocks/utils.ts"; import { Context } from "../deco.ts"; import { Murmurhash3 } from "../deps.ts"; From 7823f4fe274d0c62c865da900efe56b4b0c9f907 Mon Sep 17 00:00:00 2001 From: Marcos Candeia Date: Tue, 24 Sep 2024 12:14:03 -0300 Subject: [PATCH 4/5] Remove all tsx files Signed-off-by: Marcos Candeia --- blocks/account.ts | 2 +- blocks/action.ts | 2 +- blocks/flag.ts | 2 +- blocks/function.ts | 2 +- blocks/loader.ts | 2 +- blocks/mod.ts | 2 +- blocks/section.ts | 9 +- blocks/utils.ts | 2 +- components/{JsonViewer.tsx => JsonViewer.ts} | 39 +++-- .../{LiveControls.tsx => LiveControls.ts} | 44 ++--- components/PreviewNotAvailable.ts | 11 ++ components/PreviewNotAvailable.tsx | 6 - components/StubSection.ts | 18 ++ components/StubSection.tsx | 16 -- components/{section.tsx => section.ts} | 160 +++++++++--------- deno.json | 3 +- engine/manifest/defaults.ts | 2 +- .../workspace/deco/blocks/utils.ts | 105 ------------ hooks/useDevice.ts | 2 +- hooks/useSection.ts | 2 +- mod.ts | 17 +- runtime/features/{preview.tsx => preview.ts} | 3 - runtime/features/{render.tsx => render.ts} | 29 ++-- runtime/fresh/plugin.tsx | 2 +- runtime/{handler.tsx => handler.ts} | 29 ++-- runtime/htmx/Bindings.ts | 54 ++++++ runtime/htmx/Bindings.tsx | 43 ----- runtime/htmx/{Renderer.tsx => Renderer.ts} | 36 ++-- runtime/htmx/framework.ts | 6 +- runtime/htmx/mod.ts | 4 +- runtime/mod.ts | 8 +- .../{blockPreview.tsx => blockPreview.ts} | 16 +- .../routes/{entrypoint.tsx => entrypoint.ts} | 24 +-- runtime/routes/{previews.tsx => previews.ts} | 25 +-- runtime/routes/{render.tsx => render.ts} | 5 +- utils/{metabase.tsx => metabase.ts} | 15 +- utils/mod.ts | 7 +- 37 files changed, 326 insertions(+), 428 deletions(-) rename components/{JsonViewer.tsx => JsonViewer.ts} (69%) rename components/{LiveControls.tsx => LiveControls.ts} (89%) create mode 100644 components/PreviewNotAvailable.ts delete mode 100644 components/PreviewNotAvailable.tsx create mode 100644 components/StubSection.ts delete mode 100644 components/StubSection.tsx rename components/{section.tsx => section.ts} (66%) delete mode 100644 file:/Users/marcoscandeia/workspace/deco/blocks/utils.ts rename runtime/features/{preview.tsx => preview.ts} (96%) rename runtime/features/{render.tsx => render.ts} (85%) rename runtime/{handler.tsx => handler.ts} (89%) create mode 100644 runtime/htmx/Bindings.ts delete mode 100644 runtime/htmx/Bindings.tsx rename runtime/htmx/{Renderer.tsx => Renderer.ts} (70%) rename runtime/routes/{blockPreview.tsx => blockPreview.ts} (92%) rename runtime/routes/{entrypoint.tsx => entrypoint.ts} (89%) rename runtime/routes/{previews.tsx => previews.ts} (75%) rename runtime/routes/{render.tsx => render.ts} (96%) rename utils/{metabase.tsx => metabase.ts} (54%) diff --git a/blocks/account.ts b/blocks/account.ts index 8f69bbfca..a725fe17f 100644 --- a/blocks/account.ts +++ b/blocks/account.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-explicit-any -import JsonViewer from "../components/JsonViewer.tsx"; +import JsonViewer from "../components/JsonViewer.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; // deno-lint-ignore no-empty-interface diff --git a/blocks/action.ts b/blocks/action.ts index 6f940fe2c..afe770d28 100644 --- a/blocks/action.ts +++ b/blocks/action.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-explicit-any -import JsonViewer from "../components/JsonViewer.tsx"; +import JsonViewer from "../components/JsonViewer.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; import { applyProps, type FnProps } from "./utils.ts"; diff --git a/blocks/flag.ts b/blocks/flag.ts index 17d02915a..3b2d3f92c 100644 --- a/blocks/flag.ts +++ b/blocks/flag.ts @@ -1,6 +1,6 @@ import type { HttpContext } from "../blocks/handler.ts"; import type { Matcher } from "../blocks/matcher.ts"; -import JsonViewer from "../components/JsonViewer.tsx"; +import JsonViewer from "../components/JsonViewer.ts"; import type { TsType, TsTypeReference } from "../deps.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; import { isDeferred } from "../engine/core/resolver.ts"; diff --git a/blocks/function.ts b/blocks/function.ts index c451e97d3..ad9cf1b5c 100644 --- a/blocks/function.ts +++ b/blocks/function.ts @@ -5,7 +5,7 @@ import { newSingleFlightGroup, type SingleFlightKeyFunc, } from "../blocks/utils.ts"; -import JsonViewer from "../components/JsonViewer.tsx"; +import JsonViewer from "../components/JsonViewer.ts"; import type { Block, BlockModule } from "../engine/block.ts"; import type { HandlerContext } from "../engine/manifest/manifest.ts"; import type { DecoState, LoaderFunction } from "../types.ts"; diff --git a/blocks/loader.ts b/blocks/loader.ts index 09b922e1d..5b887ec49 100644 --- a/blocks/loader.ts +++ b/blocks/loader.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-explicit-any -import JsonViewer from "../components/JsonViewer.tsx"; +import JsonViewer from "../components/JsonViewer.ts"; import { RequestContext } from "../deco.ts"; import { ValueType, weakcache } from "../deps.ts"; import type { Block, BlockModule, InstanceOf } from "../engine/block.ts"; diff --git a/blocks/mod.ts b/blocks/mod.ts index 19a530f2a..b30e2846a 100644 --- a/blocks/mod.ts +++ b/blocks/mod.ts @@ -1,7 +1,7 @@ export type { WorkflowGen } from "@deco/durable"; export { SectionContext as SectionCtx, type SectionContext -} from "../components/section.tsx"; +} from "../components/section.ts"; export type { ComponentFunc, ComponentMetadata } from "../engine/block.ts"; export type { Resolvable } from "../engine/core/resolver.ts"; export type { Accounts } from "./account.ts"; diff --git a/blocks/section.ts b/blocks/section.ts index 8ae39d333..b1b264679 100644 --- a/blocks/section.ts +++ b/blocks/section.ts @@ -3,8 +3,8 @@ import type { ComponentType, JSX } from "preact"; import type { AppManifest } from "../blocks/app.ts"; import type { HttpContext } from "../blocks/handler.ts"; import { type PropsLoader, propsLoader } from "../blocks/propsLoader.ts"; -import StubSection, { Empty } from "../components/StubSection.tsx"; -import { alwaysThrow, withSection } from "../components/section.tsx"; +import StubSection, { Empty } from "../components/StubSection.ts"; +import { alwaysThrow, withSection } from "../components/section.ts"; import { Context } from "../deco.ts"; import type { DeepPartial } from "../deps.ts"; import type { @@ -16,10 +16,7 @@ import type { } from "../engine/block.ts"; import type { Resolver } from "../engine/core/resolver.ts"; import { HttpError } from "../engine/errors.ts"; -import { - fnContextFromHttpContext, - type RequestState, -} from "./utils.ts"; +import { fnContextFromHttpContext, type RequestState } from "./utils.ts"; /** * @widget none diff --git a/blocks/utils.ts b/blocks/utils.ts index 7ededd3ff..26ff08e80 100644 --- a/blocks/utils.ts +++ b/blocks/utils.ts @@ -2,7 +2,7 @@ import type { StatusCode as Status } from "@std/http/status"; import type { JSX } from "preact"; import type { InvocationFunc } from "../clients/withManifest.ts"; -import { withSection } from "../components/section.tsx"; +import { withSection } from "../components/section.ts"; import type { Block, BlockModule, diff --git a/components/JsonViewer.tsx b/components/JsonViewer.ts similarity index 69% rename from components/JsonViewer.tsx rename to components/JsonViewer.ts index 557cd328e..3ffc6d570 100644 --- a/components/JsonViewer.tsx +++ b/components/JsonViewer.ts @@ -1,8 +1,10 @@ -/** @jsxRuntime automatic */ -/** @jsxImportSource preact */ - -import { useFramework } from "../runtime/handler.tsx"; import type { JSX } from "preact"; +import { + Fragment as _Fragment, + jsx as _jsx, + jsxs as _jsxs, +} from "preact/jsx-runtime"; +import { useFramework } from "../runtime/handler.ts"; export interface Props { body: string; @@ -52,16 +54,21 @@ const snippet = (json: string) => { */ export default function JsonViewer(p: Props): JSX.Element { const { Head } = useFramework(); - return ( - <> - {/** @ts-ignore: could not type it well */} - -