Giter VIP home page Giter VIP logo

create-vite-plugin-ssr's Introduction

create-vite-plugin-ssr's People

Contributors

brillout avatar jrson83 avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

brillout

create-vite-plugin-ssr's Issues

CLI selectOption conditions

So we have the following selectOptions for the CLI:

VITE_APP_FRAMEWORK
VITE_APP_TYPESCRIPT
VITE_APP_CLIENT_ROUTING
VITE_APP_EJECT_RENDERER
VITE_APP_RPC
VITE_APP_PRERENDERING

For VITE_APP_FRAMEWORK & VITE_APP_TYPESCRIPT I know what todo.

For VITE_APP_CLIENT_ROUTING I'm guided by the docs and the preact-client-routing and preact-server-routing examples.

For VITE_APP_EJECT_RENDERER I don't know what todo, since I can't find any docs or examples about.

For VITE_APP_RPC it is the same (or does this depend on Wildcard API (RPC)?)

For VITE_APP_PRERENDERING the condition is just a additional line inside package.json as far as I understand:

"build:prerender": "vite-plugin-ssr prerender"

Could you please help me out with the missing information?

MVP

I think we now have covered all features we wanted for the MVP, right? The only thing missing is to stitch everything together.

We can then replace the current create-vite-plugin-ssr package.

Let's add Telefunc and other features, later.

Restructuring concepts and implementation

I've been thinking about optimizing the user CLI in the last few days, in relation to what you said in the phone conversation.

What we want for the User CLI (experience):

  • Fast installation
  • As few dependencies as possible

Restructuring

I propose the following concept:

create-vite-plugin-ssr/
โ”œโ”€ boilerplate/
โ”‚  โ”œโ”€ shared/
โ”‚  โ”œโ”€ template-preact/
โ”‚  โ”œโ”€ template-react/
โ”‚  โ”œโ”€ template-vue/
โ”œโ”€ cli/
โ”œโ”€ generator/
โ”œโ”€ templates/
โ”‚  โ”œโ”€ preact-ts/
โ”‚  โ”œโ”€ react-ts/
โ”‚  โ”œโ”€ vue-ts/
โ”‚  โ”œโ”€ preact/
โ”‚  โ”œโ”€ react/
โ”‚  โ”œโ”€ vue/

boilerplate

  • Restructuring as monorepo (one folder each framework, and in shared stuff like .css .svg server.ts)
  • We outsource the complete generator from cli to boilerplate generator
  • We add two commands for building static templates from the boilerplates
    • npm run build:ts; generates all static ts templates from boilerplate-source with async operations
    • npm run build:js: generates all static js templates from ts-source with async operations using detype
    • No CLI or progress for this, just console.log when operations are completed

cli

  • The select-cli remains as it is
  • The NPM package only includes cli & templates folder, not the boilerplate & generator folders
  • When the user selection is done, the selected template is just copied from templates
  • No async operations and no progress stuff, just console.log when operations are completed

Maybe we come up with an idea, to break it down to ts & js template folders and run a modification to insert rpc, client-routing & pre-rendering with the CLI.

EDIT

  • When the user selection is done, the CLI generates a template from ui-ts or ui folder based on selectOptions, async and with progress. So it modifies the existing template based on selections:

    • client-routing
    • rpc
    • prerendering
โ”‚  โ”œโ”€ preact-ts-client-routing/
โ”‚  โ”œโ”€ preact-ts-rpc/
โ”‚  โ”œโ”€ preact-ts-rpc-client-routing/
โ”‚  โ”œโ”€ react-ts-client-routing/
โ”‚  โ”œโ”€ react-ts-rpc/
โ”‚  โ”œโ”€ react-ts-rpc-client-routing/
โ”‚  โ”œโ”€ vue-ts-client-routing/
โ”‚  โ”œโ”€ vue-ts-rpc-client-routing/
โ”‚  โ”œโ”€ preact-client-routing/
โ”‚  โ”œโ”€ preact-rpc/
โ”‚  โ”œโ”€ preact-rpc-client-routing/
โ”‚  โ”œโ”€ react-client-routing/
โ”‚  โ”œโ”€ react-rpc/
โ”‚  โ”œโ”€ react-rpc-client-routing/
โ”‚  โ”œโ”€ vue-client-routing/
โ”‚  โ”œโ”€ vue-rpc/
โ”‚  โ”œโ”€ vue-rpc-client-routing/

The boilerplate folder will have the package.json with all dependencies. The template folder just definitions e.g.:

{
  "name": "@create-vite-plugin-ssr/template-preact",
  "private": false,
  "devDependencies": {
    "@create-vite-plugin-ssr/shared": "workspace:^"
  }
}

Reasons

  1. I don't like the mixed structure of different files and frameworks like it is at the moment. It is not consistent to have two frameworks like react & preact in one file, but vue inside another file, but just for some files and then even mixed files with all 3 frameworks.

  2. The idea to dynamic import frameworks based on a condition VITE_APP_FRAMEWORK is actually really nice and I like it. It is working fine for development (apart from point 3. intellisense). But when it comes to generating the code from the files, there has to be done the purging (which I actually also really like). In addition the await imports have to be replaced with real imports and the unused let have to be removed, with this regex, I also really like to show the already working code:

const regexDynamicImport = /(?<import>[a-zA-Z]+) ?=.*await import\(['"](?<lib>[a-zA-Z\.\/-]+)['"]\).*/gm
const regexUndefinedLet = /^let\s(?<variable>[a-zA-Z]+)\:\s(?<type>(.*?)+)$/gm

function removeIfBlocks(code) {
  ...
  code = code.replace(regexUndefinedLet, ``)
  code = code.replace(regexDynamicImport, `import $<import> from '$<lib>'`)
  ...
}

But this is sadly not all, since you also have to deal with the type imports of different frameworks and in addition create a config like thing, to tell the generator which files to actually generate for which framework. Plus if you even think of the other selectOptions like client routing & rpc, that to maintain goes beyond the scope. Plus plus, since react@18 is using different render functions and packages now, it all makes it much more complicated. I think programming and maintaining such a generator is much more work than editing a few files for changes. In addition, adding a new framework to the boilerplate would be a lot of work. It's not worth the effort just to have one file for currently "two frameworks" (Preact & React), because as you can see Vue needs its own files. Man, I really wanted to get this working, since the concept is awesome. But this all in all finally brought me to the point to consider a monorepo for the frameworks (which I had already in mind before some weeks).

  1. It is problematic to get vs code typescript intellisense working correct with the approach of mixed files. As an alternative I tried using unplugin-auto-import to import frameworks conditionally like I showed allready, here an excerpt of the code. It is also a nice but not working concept, since everytime you run npm run dev:framework, it generates a d.ts file for the current selected framework.
if (VITE_APP_FRAMEWORK === 'Preact') {
    autoImports = {
      include: [/\.[tj]sx?$/],
      imports: [
        'preact',
        { ['preact']: ['createContext', 'Fragment', 'hydrate'] },
        { ['preact-render-to-string']: [['default', 'renderToString']] },
        { ['vite-plugin-ssr']: ['escapeInject', 'dangerouslySkipEscape'] },
        { ['vite-plugin-ssr/client']: ['getPage'] }
      ],
      dirs,
      dts
    }

    runTime = {
      'preact/jsx-runtime': 'preact/jsx-runtime'
    }
  }

Current State

2022-06-03_11h57_10

Btw. fatih did great job with detype, we for sure should use this to generate the js.

I think going with the monorepo of frameworks inside the create monorepo is the way to go. Currently I only have a problem, because it is not possible to tell vps to exclude one framework folder, when building the selected. I tried:

esbuild: {
  exclude: ['template-preact/**/*', 'template-vue/**/*']
},
build: {
  rollupOptions: {
  // Externalize deps that shouldn't be bundled
  external: ['template-preact/**/*', 'template-vue/**/*'],
}

It seems they are excluded from the build, but vps does not exclude them. So I currently have to think about how to fix the error with multiple error pages, since every framework has its own _error.page.* in renderer.

I fix the root for every framework:

// _default.page.route.ts
export const filesystemRoutingRoot = import.meta.env.VITE_APP_FRAMEWORK === 'Preact' ? '/' : '/noop'

What do you think?

Is this actually a monorepo, or stereorepo then? ๐Ÿ˜Œ

I keep it going and commit the new stuff soon.

Monorepo architecture

How about:

  • pacakges/create-vite-plugin-ssr
  • packages/build
  • packages/cli

That's it.

Where:

// packages/create-vite-plugin-ssr/package.json
{
  "name": "create-vite-plugin-ssr"
  // ...
}
// packages/build/package.json
{
  "name": "@awesome-scaffolder/build"
  // ...
}

We need a cool name for our scaffolding tech :-)

// packages/cli/package.json
{
  "name": "@awesome-scaffolder/cli"
  // ...
}

We need two npm pacakges because @awesome-scaffolder/cli is included in the npm package create-vite-plugin-ssr whereas @awesome-scaffolder/build is a dev dependency.

# Source files, checked in GitHub, not published to npm
pacakges/create-vite-plugin-ssr/boilerplates/preact
pacakges/create-vite-plugin-ssr/boilerplates/react
pacakges/create-vite-plugin-ssr/boilerplates/vue

# Generated files, pubslished to npm and not GitHub
pacakges/create-vite-plugin-ssr/templates/preact
pacakges/create-vite-plugin-ssr/templates/preact-js
pacakges/create-vite-plugin-ssr/templates/react
pacakges/create-vite-plugin-ssr/templates/react-js
pacakges/create-vite-plugin-ssr/templates/vue
pacakges/create-vite-plugin-ssr/templates/vue-js

# Config for `@awesome-scaffolder`
packages/create-vite-plugin-ssr/scaffold.config.ts
# Build script that generates the `templates/` dirS
packages/create-vite-plugin-ssr/build.ts
// packages/create-vite-plugin-ssr/build.ts

import scaffoldConfig from './scaffolder.config'
import awesomeScaffolder from 'awesome-scaffolder'

build()

async funciton build() {
  await awesomeScaffolder(scaffoldConfig)
}

Eventually, in the future, create-vite-plugin-ssr and @awesome-scaffolder would live in two different repositories.

Use Vitest

Before tackling #8 I highly recommend using Vitest.

It's a LOT of fun :-). It will make implementing #8 a breeze.

Directory Conflict Resolving

How about this:

  1. By default it creates vite-app/. The user cannot change that (with the exception explained in 3.).

  2. If vite-app already exists, a yellow warning is shown:

    vite-app/ already exists and will be overwritten.

    The only way for the user to avoid the dir to be overwritten is to exit the CLI. In other words, a single <enter> press is still enough to confirm everything.

  3. In the warning we can inform the user about a shortcut:

    Press <r> to rename the created directory vite-app/.

If the warning is not shown there is no mention that the name of the directory is vite-app/, and we don't inform the user about the <r> shortcut. It just creates it without prompting the user. The idea here is that users can mv the directory if they want to rename the directory. (Note we don't define any package.json#name; it's useless for apps.)

Let me know if you have any thoughts or objections.

Scaffolding Logic

How about this:

if (import.meta.IS_PREACT) {
   // Preact variant
}
if (import.meta.IS_VUE) {
   // Vue variant
}
// etc.

The neat thing here is that we simply develop one big app that contains all variants. We can use IntelliSense, TypeScript, etc. just like a normal app.

Maybe we can remove the irrelevant if-blocks without any AST:

  1. We look for the string if (import.meta.IS_PREACT) { (we throw an error if we detect non-prettier syntax, e.g. if(import.meta.IS_PREACT){.
  2. We look for } with the same space padding. (When prettier is applied I believe this is a reliable way to get the end of the block.)

Or we use an AST, whatever seems easiest.

@cyco130 FYI (author of https://github.com/cyco130/create-vike)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.