A super fast SSR framework for Vue.js.
❤️ Please sponsor me to support this project or prioritize a feature you want. I will work on this project for full-time once I have 150+ sponsors.
Documentation (WIP)
MIT © EGOIST
A Vue 3 framework, powered by Vite.
Home Page: https://ream.dev
License: MIT License
A super fast SSR framework for Vue.js.
❤️ Please sponsor me to support this project or prioritize a feature you want. I will work on this project for full-time once I have 150+ sponsors.
Documentation (WIP)
MIT © EGOIST
Two types of pages are recognized as API routes:
.***.{js,ts}
, e.g. pages/posts.json.js
pages/api/
sub directory and ending with .{js,ts}
, e.g. pages/api/graphql.js
An API route should export an HTTP request handler:
export default (req, res) => {
res.end('hey')
}
Let me know what you think
export const preload = (ctx) => {
if (!isAuthed(ctx.req)) {
return { redirect: '/login' }
}
return { data: {} }
}
Vue 3 is coming soon so I wonder if it's good idea to support Vue 3 only, let me know what you think. 👀
It should scroll to top after navigating to a new page.
Allow to create a route structure like:
{
path: '/settings',
component: Settings,
children: [
{ path: '', component: SettingsHome },
{ path: 'account', component: SettingsAccount }
]
}
Build a plugin to add progressive web app support to your website.
To achieve this we need to update the plugin API, a new hook is needed:
onPostBuild
: Called when the build process is completed.I'm very interested in using this project when it's released!
Is there a roadmap or something similar that shows how this project is progressing?
CSS support currently is a prototype, todos:
The children of ClientOnly
will only be rendered on the client side, you can use it with defineAsyncComponent
to disable SSR for specific pages.
It should serve files inside ./public
at root path, for example ./public/style.css
will be accessible at /style.css
Obviously this is for server
target only.
I've done this in Saber, let me (or you) do some copy paste work.
If you try to fetch the page in the page's preload
function, you'll enter an infinite loop.
// pages/foo.vue
import { fetch } from 'saber/fetch'
export const preload = async () => {
await fetch('/foo')
}
It's possible with the new Ream architecture, I'll take a look at this (or at least document how to do it yourself) when the core and Vue integration are settled.
If you also want this to happen, hit 👍
pages/_error.vue
pages/404.vue
Hey,
I wanted to discuss about few things concerning languages.
Locale is a code of ISO 639-1 or combination of ISO 639-1 and ISO 3166-1 alpha-2, with a hyphen (i.e. 'en-US').
Currently, most common and recommended approach is to add locale as first param: /[locale]/[...otherParams]
.
Nuxt provides us with: https://i18n.nuxtjs.org/
My locale list in most cases is a dynamic response from API (Translation platform). And that's why I need to write custom functions for:
There are three types of translations that I'm interested in:
select
element.It would be nice to be able to translate URLs like this:
/[locale]/[category]/[product].vue
/en/fridges/snowflake-3000
/lt/šaldytuvai/snaigė-3000
Cloning ream
run yarn
run yarn build
run yarn link
in ream package
run yarn link ream
in website
run yarn dev
I get
Preparing Ream files
√ Client
Compiled successfully in 1.09m
√ Server
Compiled successfully in 1.07m
> http://localhost:3000
You are running a development build of Vue.
Make sure to use the production build (*.prod.js) when deploying for production.
You are running the esm-bundler build of Vue. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle. See http://link.vuejs.org/feature-flags for more details.
[Vue warn]: Unhandled error during execution of setup function
at <RouterView>
server error TypeError: Cannot read property 'parent' of null
at warnDeprecatedUsage (C:\Users\Nabil\Project\ream\website\.ream\server\main.js:12972:33)
at setup (C:\Users\Nabil\Project\ream\website\.ream\server\main.js:12915:20)
at callWithErrorHandling (C:\Users\Nabil\Project\ream\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:156:22)
at setupStatefulComponent (C:\Users\Nabil\Project\ream\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:5687:29)
at setupComponent (C:\Users\Nabil\Project\ream\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:5648:11)
at renderComponentVNode (C:\Users\Nabil\Project\ream\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:159:17)
at renderVNode (C:\Users\Nabil\Project\ream\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:235:22)
at renderVNodeChildren (C:\Users\Nabil\Project\ream\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:250:9)
at renderVNode (C:\Users\Nabil\Project\ream\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:227:13)
at renderComponentSubTree (C:\Users\Nabil\Project\ream\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:204:13)
In development, we should only build pages that are recently visited (or active, a.k.a. not closed in browser) to speed up webpack build process.
enhance-app.js
can be used to extend your Vue app:
export const onCreatedApp = ({ app, router }) => {
// do something with the Vue app instance `app`
// or Vue router instance `router`
}
Currently, it's supported in plugins, but a project-level enhance-app.js
support is also necessary.
Introduce build-time hooks: routes
in ream.config.js
:
export default {
routes(defaultRoutes) {
return [...defaultRoutes, {path: '/foo', component: './foo.vue'}]
}
}
This is a limitation of running vue-server-renderer
with runInNewContext: false
, we can't inline critical css when the JavaScript file is lazy loaded via import()
, like all your page components.
Work around is using <style src="./some.css">
or css
option in ream.config.js
or import CSS in plugin's enhance-app.js
Currently there's basic TypeScript support that you can write .ts
files and use <script lang="ts">
block in .vue
files, what we need to add:
import { GetStaticProps } from 'ream'
It's supposed to crash currently because we haven't handled path slashes \\
when writing files to .ream
folder.
Using Ream to build a pure SPA (no server-side rendering) would be a desired feature.
You can already deploy it as a static site but it seems a bit tricky to deploy as a serverless function. I guess we'll have to create a custom Now builder. We should start this when entering RC phase.
The error causes you to have to click a link twice to actually navigate to the target page.
Culprit:
ream/packages/ream/vue-app/get-before-resolve.js
Lines 18 to 34 in 4d04f75
From vue-router 4.0.0-beta.5, it will warn if guard returns without calling next. Maybe you have to return a promise.
Page component can export function getStaticProps
, and we will run it on the server side at build time.
Since it's only used in build time you can't access stuff like req.query
, if the route path contains paramater like /post/:slug
, you also need to export a function getStaticPaths
which returns a set of static paths so we can use it to render the page.
The underlying server Ream uses is created by using Express.js.
Why Express:
Why not Express:
At the moment we can use a hook onCreatedApp
in enchance-app.ts
where we have an access to app
, router
and initiateState
.
If I add a new route using router API (e.g router.addRoute({...}) this route will work only after the application loaded in the browser. So I can go to this new page, and it will be rendered.
But if I reload the page it will give me 404 error. It happens because this hook onCreatedApp
has not been taken to consideration during SSR.
Thank you for this framework.
Ream support two build targets:
getStaticProps
to fetch data at build time if you want.getServerSideProps
won't be available for this target.The default target is server, you can switch it by appending flag --target static
Currently, only very basic server logic can be implemented comfortably using Ream. Maybe using an enhance-server.ts
file, server hooks could be used to implement for example middleware. Just one example:
// enhance-server.ts
export const onCreatedApp = ({ server }) => {
server.post('/api/register', (req) => {
db.users.add({ username: req.query.username })
})
const websocket = new myWebsocketMiddleware()
server.use(websocket)
}
Or possibly consolidated with the pages/api/
system:
// pages/api/users.ts
import { server } from '@ream/server'
server.use(authMiddleware) // middleware all /api/users/* routes
server.post('/register', handleRegistration) // mapped to /api/users/register
<script>
import fs from 'fs'
export const preload = () => {
return {
data: {
content: fs.readFileSync('foo.md', 'utf8')
}
}
}
</script>
<script setup>
// ...
</script>
fs
will be unexpectedly added to setup()
function even if it's not imported in <script setup>
but a regular <script>
block, this is a known issue of @vue/compiler-sfc
.
The workaround is to not to use preload
with the <script setup>
block.
should be flexible enough so we can use it to build another framework, for example a gatsby-like static site generator
Plugin folder structure:
- my-plugin/
index.js
enhance-app.js
enhance-server.js
Use a plugin in config file:
// ream-config.js
module.exports = {
plugins: [
['./plugins/my-plugin', {/* options */}],
['ream-plugin-foo', {}],
'@ream/plugin-bar'
]
}
We can traverse through the Vite moduleGraph to get imported css during dev.
Modifying the preload
function in a page won't trigger hot reloading, kinda expected but it can be fixed.
import nossr from 'ream/nossr'
const ButtonWithoutSSR = nossr(() => import('./button.vue'))
Use these entry files to customize server and client app.
E.g. entry-client.js
:
import { getContext, createApp } from '@ream/app'
const context = getContext()
const { router } = createApp(context)
router.beforeEach((to, from, next) => {
// start progress bar
})
router.afterEach(() => {
// stop progress bar
})
That requires us to introduce a config file first.
TODOS:
ream export
, exporting pages to static HTML files, "API pages" are also supportedpreload
export on page componentsTo achieve something like this: https://router.vuejs.org/guide/essentials/nested-routes.html
[
{
path: '/gists',
component: 'gists.vue',
children: [
{ path: '', component: 'gists/index.vue' },
{ path: ':user', component: 'gists/[user].vue' }
]
}
]
You can use file system based routes like this:
--- gists.vue
--- gists/
--- index.vue
--- [user].vue
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.