netzo / fresh-netzo

Full-stack Deno Fresh meta-framework for building business web apps like internal tools, dashboards, admin panels and automated workflows.
https://netzo.io
MIT License
51 stars 3 forks source link

[cli] broken `netzo deploy` due to import paths #130

Closed miguelrk closed 9 months ago

miguelrk commented 9 months ago

See #https://github.com/netzo/netzo/issues/129

For reference, I just did netzo init crm and then netzo deploy and it did work:

netzo deploy
✔ Project: CRM
ℹ Uploading all files from the current dir (/home/mrk/playground/crm)
✔ Found 65 assets.
Warning: Not implemented: ClientRequest.options.createConnection
✔ Packaging complete
✔ Deployed to https://netzo-crm-shmm34wyhqz3.deno.dev

Open in netzo at https://app.netzo.io/workspaces/64129a023cdd8d467c251168/projects/65880027888e3d8d6115c784

but netzo init minimal and then netzo deploy failed:

netzo deploy
✔ Project: Minimal
ℹ Empty project detected, automatically pushing initial deployment to production (use --production for further updates).
ℹ Uploading all files from the current dir (/home/mrk/playground/minimal)
✔ Found 9 assets.
Warning: Not implemented: ClientRequest.options.createConnection
✔ Packaging complete
✖ Deployment failed.

error: The deployment failed: UNCAUGHT_EXCEPTION

TypeError: module not found: 'https://deno.land/x/netzo@0.4.37/components/layout/footer.tsx'
    at async extractRoutes (https://deno.land/x/fresh@1.6.3/src/server/fs_extract.ts:249:22)
    at async getServerContext (https://deno.land/x/fresh@1.6.3/src/server/context.ts:82:25)
    at async start (https://deno.land/x/fresh@1.6.3/src/server/mod.ts:110:15)

Both tested with netzo@0.4.37. This helps narrowing down the cause, I will continue investigating... The strange thing is that https://deno.land/x/netzo@0.4.37/components/layout/footer.tsx appears to not be found, but it does indeed exists (we can navigate to it).

miguelrk commented 9 months ago

So deploying the crm template works ✅, deploying the minimal template doesn't ❌ .

Workaround: After adding a routes/_app.tsx file to the minimal template, the deployment worked.

Issue: I'm guessing this has to do with the netzo/plugins/components plugin auto-injecting islands via

// netzo/plugins/components/plugin.ts
export const components = (options?: ComponentsConfig): Plugin => {
  // ...
  return {
    ...unocss({ options: { color, radius }, config, aot, ssr, csr }), // { name, entrypoints, renderAsync, buildStart }
    name: "components",
    islands: {
      baseLocation: import.meta.url,
      paths: [
        "../../components/layout/footer.tsx",
        "../../components/layout/header.tsx",
        "../../components/layout/nav.tsx",
        "../../components/layout/nav.mobile.tsx",
      ],
    },
  };
};

causing the TypeError: module not found: 'https://deno.land/x/netzo@0.4.37/components/layout/footer.tsx' error above somehow, probably since an island is being injected but never actually used by the app. Which explains why when we add the _app.tsx which uses the <Layout.Footer /> component, then it does work. Using the current fresh canary version also did not fix it...

miguelrk commented 9 months ago

Fixed by https://github.com/netzo/netzo/releases/tag/0.4.39

Issue: As mentioned above, the deployment issue for the minimal template ended up being missing netzo/components/layout imports (since the minimal template does not have an _app.tsx which uses them) and the netzo/plugins/components was still registering them as islands.

Solution: remove the island registration from netzo/plugins/components in favor of locally re-exporting the layout components (and eventually also others) from a local @/islands/mod.ts file. This pattern is really not that bad after all and could even be improved in the future once and if https://github.com/denoland/fresh/pull/2301 and maybe https://github.com/denoland/fresh/pull/2275 are merged.

deer commented 9 months ago

Sorry, somehow I don't get it. Can you please clarify further? When I started the project locally it worked just fine. I'm still unclear why the deployment failed.

miguelrk commented 9 months ago

Sure @deer, the deployment failing was due to the netzo/plugins/components plugin injecting islands via

// netzo/plugins/components/plugin.ts
export const components = (options?: ComponentsConfig): Plugin => {
  // ...
  return {
    ...unocss({ options: { color, radius }, config, aot, ssr, csr }), // { name, entrypoints, renderAsync, buildStart }
    name: "components",
    islands: {
      baseLocation: import.meta.url,
      paths: [
        "../../components/layout/footer.tsx",
        "../../components/layout/header.tsx",
        "../../components/layout/nav.tsx",
        "../../components/layout/nav.mobile.tsx",
      ],
    },
  };
};

and the app not importing/using them anywhere. This was only an issue with the minimal template, which does not have an _app.tsx file that imports/uses these layout components. The crm template on the other hand does have an _app.tsx file which was doing import * as Layout from "netzo/components/layout/mod.ts", so that didn't break on deployment.

I'm not entirely sure why this breaks only on deployment (since both work locally totally fine), but I suspect that it has to do with the module resolution logic for injected islands over at fresh. If its not on fresh's side, then it might be module resolution on the Subhosting side, since the "deploy" subcommand really only does a POST /projects/{projectId}/deployments (but that I cannot unfortunately not tap into).

In any case, what https://github.com/netzo/netzo/releases/tag/0.4.39 does to fix this is simply define a local @/islands/mod.ts file:

// NOTE: re-export specific components from islands/ for reactivity
export * from "netzo/components/layout/mod.ts";

and then simply import from there import * as Layout from "../islands/mod.ts";. This is obviously only required when using an _app.tsx file with netzo's layout components (since some require being islands for reactivity). I'm fine with this solution, since this way the netzo/plugins/components only concerns itself with the theme, for now, rather than with injecting islands which the user still has to use (since we no longer inject a pre-defined _app route). This also reduces the "scope" of netzo/plugins/components.