Giter Site home page Giter Site logo

shuvijs / shuvi Goto Github PK

View Code? Open in Web Editor NEW
27.0 3.0 13.0 8.17 MB

Nextjs, but for SPA, no server required

Home Page: https://shuvijs.github.io/shuvijs.org/

JavaScript 9.97% TypeScript 78.91% Shell 0.01% EJS 0.01% Rust 10.86% HTML 0.04% CSS 0.21%
react server-rendering shuvi universal shuvijs vue nextjs spa

shuvi's People

Contributors

andy-yuanchang avatar evenchange4 avatar harrytothemoon avatar ives7 avatar kayneluo avatar li2568261 avatar liximomo avatar nieheyong avatar panghu-huang avatar repraance avatar thuyduc1995 avatar wangjinyang avatar zadzbw avatar zhengyutay 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

Watchers

 avatar  avatar  avatar

shuvi's Issues

[RFC] Eslint-plugin-shuvi no-process-electron

Eslint-plugin-shuvi

Create a new eslint plugin with custom rules so that user can follow.

Rule: no-process-electron

Disallow the use of process.electron

This rule is aimed at discouraging use of process.electron to avoid complex cross-platform code. As such, it will warn whenever process.electron is used.

Examples of incorrect code for this rule:
// components/Layout.js

// Unexpected use of process.electron (at 8:14)
const link = process.electron ? "a" : "b";
// -------------^
Examples of correct code for this rule:

It is recommended to use platform-specific extensions.

- components/Layout.js
+ components/Layout/index.web.js
+ components/Layout/index.electron.js
// components/Layout/index.web.js
const link = "b";

// components/Layout/index.electron.js
const link = "a";

Implementation

https://astexplorer.net/#/gist/7778d0e445ca638078814cca4e0ea1d5/b05826e1eca1512b8ef8ed855af4afe364ffe82b

wrong history when using client side loader redirect

问题

我们发现,如果在client side路由导航时,loader 中使用redirect,那么跳转之后,浏览器历史会发生错误。

例子

假设,有/a,/b,/c 三个页面,其中,a 页面有一个link按钮,可以跳转到b。b 的 loader 里会 redirect 到 c。

在浏览器的空白tab中访问a页面,然后点击link按钮跳转至 b 时,成功重定向至c页面,到此为止,都是正常的。
但此时点击后退,直接后退到了空白tab,即,历浏览器history记录中的a页面没了。

期望行为

在c页面点击后退,应该后退至a页面。

问题定位

问题出在 loader 的 redirect 逻辑中,
更进一步的说,是 router 前置钩子中next的逻辑的问题导致的。

client loader 执行时,如果有redirect,会调用next方法进行路由跳转的重定向,其中,next的参数传了redirect: true

代码位置

image

问题正出在redirect选项上。
代码位置
image
可以看到,如果next的参数带有redirect:true,router会中止当前跳转并重新发起一个replace。

拿刚才a b c 页面的例子带入一下,也就是说,原本 a -> b 的 push 操作被中止,然后重新发起一个 a -> c 的 replace。
这样一来,跳转完成之后,a 页面的历史记录确实就被替换了。这便是例子中问题的原因所在。

进一步的分析

问题的核心在于路由前置钩子中next的逻辑。
经过分析,我发现next不应该有redirect参数。换句话说,redirect本身是没有push还是replace的选项的。
push和replace应该由原本的路由跳转所决定。

比如,还是刚才的例子,原始的跳转是 a -> b (push),那么redirect只是更换了target location而已,原始跳转是push,那么重新发起的路由跳转也是push。

如果原始的跳转是 a -> b (replace),而b 页面会redirect 到 c,那么重新发起的 a -> c 跳转也应该是 replace。

其他框架的做法

因为问题出在router 钩子逻辑中,而 next.js,remix 都没有router 钩子,所以不能参考。
shuvi-router 本身是参考vue-router的,所以这里看了一下vue的做法。

可以看到,vue-router中,重新发起route transition时,会保留当前的replace选项,并允许本次redirect进行覆盖。
代码位置
image

相比之下,这确实是一个比较好的策略。
默认情况下,redirect的push和replace由原本的路由跳转所决定。同时,redirect也可以覆盖设置。

例子:
在beforeEach钩子中进行重定向,并且把redirect方式覆盖为replace

router.beforeEach((to, from, next) => {
  if (to.path === '/b') {
    next({ name: 'c', replace: true })
  }
  next()
})

解决方案

对标vue-router的策略,当路由前置钩子中通过next进行redirect时,保留原始的push/replace,并允许覆盖。
但是,因为shuvi这边承载 next 逻辑的 _doTransition 方法中,没有replace 参数,因此,为了能够判断原始的跳转方式,需要增加参数。

[RFC] Server Middleware and Custom API endpoint

Problems

  • For SSR, most of the time, user need to define their own custom API endpoint. Some of the example could be healthcheck or an API proxy. This could be anything. It is essential for us to implement this.

    Other than that, user need to have custom header. This is for use case like CSP or caching purposes for each of our pages in SSR.

    Refer to serverMiddleware by nuxt.js for more example.

  • For isomorphic use case, middleware can mean that a layer before entering our application/page. I think this can be done already with our navigation guard of router. #62 . But we can look more into this if there is a need to have a separate middleware for our application.

Proposal

We can have a serverMiddleware in our config like nuxt.js which can apply a global middleware to all our pages or specific pages with path specified.

Example:
shuvi.config.js

{
	serverMiddleware: [
		'auth', // global middleware (npm)
		{ path: '/home', handler: 'api/home' } // route based middleware
	]
}

api/home (middleware example)

interface MiddlewareContext {
	req: Request,
	res: Response,
	next: Function
	send: (result)=> void // if send is called the middleware exit and response, else continue render page
}
export default (context:MiddlewareContext) => {
	context.res.setHeader('Custom', 'value')
	if(condition){
		context.send('end'); // you can modify result to any
		return;
	}
	context.next();
}

context can contain req and res. Might be better to make it support async await and not use (req, res, next).

Reference

Nextjs

Nuxtjs

相对路径的redirect问题

问题

在修复 #563 时,我发现e2e tests 里包含SSR时,相对路径的redirect。

一般来说,我们的功能应该是同构的,因为我也增加了CSR的对应e2e test,随后发现CSR时,相对路径的redirect无法正常工作。

例子

具体来说。

SSR 相对路径的redirect 的test case,是正常的。假设我们有以下页面

/
/c
/x,其loader会return redirect('c') 即相对路径redirect
/x/c

当SSR时,直接访问/x,会302到/x/c,相当于,此次redirect是基于/x的。这是我们的当前预期。

然而,当前端路由跳转时,如,在/页面,点击/x的链接,结果却跳到了/c 页面,也就是说,此处redirect是基于跳转前的路径/

同时,当在SPA模式下,直接访问/x,页面url会跳转至/x/c,但是页面显示404。这里应该是另一个bug

也就是说,对于同一个页面,不同情况下的访问表现出截然不同的行为。

分析

我认为,相对路径的redirect,是一个bad practice。

通常来说,前端路由导航由页面中的链接按钮触发,当点击链接导航时,可以是相对路径,并且是由跳转之前的url为base url。
也就是说,对于单纯的路由导航,其跳转地址可以是相对路径,并且规则很明确。

但是对于redirect,情况则不同了。
前端路由导航中下,redirect 包含三个对象:

  • navigate from
  • navigate to
  • redirect to

如果redirect地址是一个相对路径,那么,这个是相对于navigate from,还是navigate to呢?我认为规则是不清晰的。

shuvi允许在loader中进行redirect。对于开发者来说,如果使用相对路径进行redirect,自然想到的是以loader所在的路由作为base。
但事实上,loader所在的路由是navigate to。

在上面的例子中(shuvi 的 e2e test中),SSR时访问/x,redirect至 /x/c,正是以 navigate to 作为base。

而前端路由跳转时,却redirect到 /c,此时则变成了以 navigate from 作为base。vue-router 也是如此。

其他框架的做法

使用相对路径进行redirect时,vue 的 base 是navigate from
remix 和react-router 是基于 navigate to
next.js 待确认

解决方案

相对来说,我倾向于以navigate to 作为base,比较符合直觉。

因为,无论是使用route config还是使用hook,还是loader来配置redirect。
redirect总是配置在navigate to上面的。
而navigate to是很明确的,所以这时如果有redirect,自然是应该基于当前的navigate to来计算实际路径。

另一方面,用户在跳转时,navigate from可以是任何地址。如果redirect的相对路径base是navigate from,那么最终地址也是五花八门的,是完全不可预料的,这样也就没有意义了。

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.