Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Full-stack (meta?) framework / CLI #251

Open
1 of 4 tasks
brainkim opened this issue Feb 27, 2023 · 2 comments
Open
1 of 4 tasks

Full-stack (meta?) framework / CLI #251

brainkim opened this issue Feb 27, 2023 · 2 comments
Assignees

Comments

@brainkim
Copy link
Member

brainkim commented Feb 27, 2023

The Crank.js documentation website is being built with some hacked-together code which uses ts-node, nodemon, ESBuild’s JavaScript API, a funny little router, etc. It would be nice to package this behind a CLI.

I have been putting this off for a long time because of open questions of API design, not wanting to reinvent the wheel, and the fact that bundling/transpilation continue to evolve... but perhaps it is time, especially as I rewrite the docs to handle stuff like Vite / etc. I think it is possible to do it now, especially with ESBuild. Maybe we could even put the CLI directly in the Crank package. (probably not a good idea)

Naming ideas:

  • scale scale develop (@b9g/scale)
  • captain captain develop (@b9g/captain)
  • capn capn dev (@b9g/capn)
  • something to do with gears? Web spiders?
  • I like the idea of capitalizing on c-based names
  • shovel (I keep hearing “sell shovels” bandied about).

The parts of the framework so far:

  • Basic path-to-regexp based router that doesn’t do much.
  • Client-side bundling/transpilation
    • A way to build client-side code using ESBuild using server-side components, on the fly in development.
    • A way to serve static assets.
    • A way to run the router with an array to create a static build.
  • A janky development server that goes down to new requests any time there’s a change.

Attack plan:

Development should be oriented around commands:

  • x develop (or x serve?)
  • x static
  • x init
    once a pretty and solid directory structure is discovered
  • x build and x prod (maybe rethink the names at this level)

The meta-framework will likely need to provide server-side components like the following:

  • <HTML5 /> Does the weird lil bit where you have to DOCTYPE. Maybe we could pass in our current Storage abstraction here, or it could be a separate component.
  • <Script />, <Style />, <Link /> ESBuild-backed replacements for equivalents. These components automatically build/transpile the referenced files.
  • <Client /> / <Island /> ??? A way to render stuff client-side. Could do stuff like generate renderer.hydrate code directly. May be id-based. I don’t like Island terminology but it fits with the captain nautical theme.
  • <Head />, <Body /> Components to coordinate between user code and HTML5. Could inject critical scripts top bottom head body. Or this could be done other components like <CriticalScripts />. Honestly a lot of ways to design the API.
  • <LiveReloadScript /> for when you want to inject live-reloading or whatever

TODO: Write hypothetical Getting Started docs.

@brainkim brainkim self-assigned this Feb 28, 2023
@brainkim
Copy link
Member Author

brainkim commented Mar 22, 2023

I have settled on the name shovel. For now. I’ve got ESBuild and node vm’s working. The develop command is useable, now I need to do static and maybe call it a day, though I’ve thought about also implementing server-side hot reloading.

I am progressing faster than I usually would, in no small part to ChatGPT.

https://github.com/bikeshaving/shovel
#255

@brainkim
Copy link
Member Author

Thinking about possible entry file exports for the static command.

Currently, I have:

export default {
  async staticPaths() {
    return [...paths];
  },
};

but I need to run additional code after paths have been turned into URLs and fetched.

Toying with some API ideas.

export default {
  async *static(dist) {
    for (const path of paths) {
      // TODO: Is there a useful yield value? The Response object? The absolute path?
      yield path;
    }
    await Storage.write("dist", );
  },
};
export default {
  async *static() {
    yield *paths; 
    await Storage.write("dist");
  },
};

The problem with naming it static, is that it’s a pseudo-keyword that will probably confuse people. So maybe just keep the same name (staticPaths) and make it polymorphic to accept async generators?

Also I don’t want to create an association that CLI commands and root default exports should have the same name. For instance, shovel develop calls the fetch() function.

export default {
  async fetch(req) {
    /* ... */
  },
  // I also like the idea of passing in the destination directory.
  async *staticPaths(outDir) {
    yield *paths;
    await Storage.write(outDir);
  },
};

Not bad...

More thoughts.

Am I still down with defining this all on the default export? Yes, I guess, in the sense that the default fetch method aligns with the way Cloudflare Workers/bun does it.

Okay I have a plan, and it won’t be a breaking change!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant