jrson83 / create-vite-plugin-ssr Goto Github PK
View Code? Open in Web Editor NEWcreate-vite-plugin-ssr wip
Home Page: https://vite-plugin-ssr.com
License: MIT License
create-vite-plugin-ssr wip
Home Page: https://vite-plugin-ssr.com
License: MIT License
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.
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?
How about this:
By default it creates vite-app/
. The user cannot change that (with the exception explained in 3.).
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.
In the warning we can inform the user about a shortcut:
Press
<r>
to rename the created directoryvite-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.
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 packagecreate-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.
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):
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
.css
.svg
server.ts
)generator
from cli
to boilerplate
generator
npm run build:ts
; generates all static ts
templates from boilerplate-source
with async
operationsnpm run build:js
: generates all static js
templates from ts-source
with async
operations using detype
console.log
when operations are completedcli
select-cli
remains as it iscli
& templates
folder, not the boilerplate
& generator
folderscopied
from templatesconsole.log
when operations are completedMaybe 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:
│ ├─ 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
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.
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).
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
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.
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:
if (import.meta.IS_PREACT) {
(we throw an error if we detect non-prettier syntax, e.g. if(import.meta.IS_PREACT){
.}
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)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.