Giter Site home page Giter Site logo

ream's Introduction

Ream

A super fast SSR framework for Vue.js.

sponsor egoist npm version build status npm downloads

❤️ 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.

Website

Documentation (WIP)

Sponsors

powered by vercel

License

MIT © EGOIST

ream's People

Contributors

0xflotus avatar dependabot-preview[bot] avatar dependabot[bot] avatar egoist avatar hebilicious avatar kidonng avatar smhmd avatar swedish-li avatar varna avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ream's Issues

[Discussion] API Routes

Current behavior

Two types of pages are recognized as API routes:

  • Filename ending with .***.{js,ts}, e.g. pages/posts.json.js
  • Populated inside 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

Allow `redirect` in preload

export const preload = (ctx) => {
  if (!isAuthed(ctx.req)) {
     return { redirect: '/login' }
  }

  return { data: {} }
}

Drop Vue 2 support?

Vue 3 is coming soon so I wonder if it's good idea to support Vue 3 only, let me know what you think. 👀

Nested routes

Allow to create a route structure like:

{
  path: '/settings',
  component: Settings,
  children: [
    { path: '', component: SettingsHome },
    { path: 'account', component: SettingsAccount }
  ]
}

PWA plugin

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.

Roadmap

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?

Complete CSS support

CSS support currently is a prototype, todos:

  • css extraction
  • css preprocesssors
  • css modules

Export a `ClientOnly` component

The children of ClientOnly will only be rendered on the client side, you can use it with defineAsyncComponent to disable SSR for specific pages.

Static file serving

It should serve files inside ./public at root path, for example ./public/style.css will be accessible at /style.css

Infinite loop in `preload` function

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')
}

Supporting React

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 👍

Translations (i18n)

Hey,

I wanted to discuss about few things concerning languages.

How do we localize?

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/

How do we deal with locale list?

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:

  • meta/head translations and canonical links
  • sitemap.xml
  • generate/export static pages

How do we import/fetch translations?

There are three types of translations that I'm interested in:

  • Page - translations needed for current page
  • Component - translations needed for current component, i.e. list of items for select element.
  • Global - globally imported translations available everywhere, also known as "Translation Project" for single App. Could also be seen as App Shell form Google or Template in Nuxt.

How can we translate links?

It would be nice to be able to translate URLs like this:

/[locale]/[category]/[product].vue
/en/fridges/snowflake-3000
/lt/šaldytuvai/snaigė-3000

Unhandled error during execution of setup function

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)

Build pages on demand

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.

Global `enhance-app.js` support

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.

Allow to add routes at build time

Introduce build-time hooks: routes in ream.config.js:

export default {
  routes(defaultRoutes) {
    return [...defaultRoutes, {path: '/foo', component: './foo.vue'}]
  }
}

Importing CSS in JavaScript will not work with SSR

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

Advanced TypeScript support

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:

  • Use fork-ts-checker-webpack-plugin when TypeScript is detected in current project
  • Document how to use the types exported by Ream, like import { GetStaticProps } from 'ream'

Windows support

It's supposed to crash currently because we haven't handled path slashes \\ when writing files to .ream folder.

[Vue warn]: The "next" callback was never called inside of "beforeResolve"

The error causes you to have to click a link twice to actually navigate to the target page.

Culprit:

const fetchProps = (next) => {
Promise.all(
[
preload && preload({ params: to.params }),
hasServerPreload &&
fetch(getServerPreloadPath(to.path)).then((res) => res.json()),
].filter(Boolean)
).then(([preloadResult, servePreloadResult]) => {
pagePropsStore[to.path] = Object.assign(
{},
preloadResult,
servePreloadResult
)
if (next) {
next()
}
})

From vue-router 4.0.0-beta.5, it will warn if guard returns without calling next. Maybe you have to return a promise.

getStaticProps

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.

Replace Express.js with something else

The underlying server Ream uses is created by using Express.js.

Why Express:

  • Full featured, out-of-the-box middleware support
  • Great ecosystem

Why not Express:

  • Bundle size is huge: a few hundred kb
  • Performance is meh

Feature request: Ability to add routes programmatically

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.

Build target: server or static

Ream support two build targets:

  • server: app is server rendered, however you can still use getStaticProps to fetch data at build time if you want.
  • static: we prerender every page to static files, getServerSideProps won't be available for this target.

The default target is server, you can switch it by appending flag --target static

Enhance server capabilities

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

Using `preload` with `<script setup>` will leak server-side imports

<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.

Plugin system

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'
  ]
}

entry-server and entry-client

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
})

🥰 Rewriting for Vue 3..

TODOS:

  • HELP WANTED: Head management plugin for Vue, like react-helmet and vue-meta, @ream/head
  • HELP WANTED: Lightweight Express/Connect alternative, we actually only need the "middleware" functionality. ream/server
  • WIP: ream export, exporting pages to static HTML files, "API pages" are also supported
  • WIP: Preloading data using preload export on page components
  • WIP: Nested routes #41
  • Error pages (404 and 500)

Nested routes

To 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

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.