├── .codesandbox └── ci.json ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.ts ├── package.json ├── packages ├── create-project │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── index.js │ ├── package.json │ ├── template-app │ │ ├── README.md │ │ ├── _gitignore │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ ├── $.mdx │ │ │ ├── _theme.tsx │ │ │ ├── dir │ │ │ │ ├── page2$.tsx │ │ │ │ └── page3 │ │ │ │ │ ├── box.module.css │ │ │ │ │ ├── box.tsx │ │ │ │ │ └── index$.mdx │ │ │ ├── page1$.tsx │ │ │ └── users │ │ │ │ ├── [userId] │ │ │ │ ├── index$.tsx │ │ │ │ └── posts │ │ │ │ │ └── [postId]$.tsx │ │ │ │ └── index$.tsx │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── template-lib-monorepo │ │ ├── README.md │ │ ├── _gitignore │ │ ├── package.json │ │ ├── packages │ │ │ ├── button │ │ │ │ ├── README.md │ │ │ │ ├── demos │ │ │ │ │ ├── demo1.tsx │ │ │ │ │ └── demo2.tsx │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ │ ├── declare.d.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── style.module.css │ │ │ │ │ └── tsconfig.json │ │ │ │ └── tsconfig.json │ │ │ ├── card │ │ │ │ ├── README.md │ │ │ │ ├── demos │ │ │ │ │ ├── demo1.tsx │ │ │ │ │ └── demo2.tsx │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ │ ├── declare.d.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── style.module.css │ │ │ │ │ └── tsconfig.json │ │ │ │ └── tsconfig.json │ │ │ └── demos │ │ │ │ ├── index.html │ │ │ │ ├── package.json │ │ │ │ ├── pages │ │ │ │ ├── $.tsx │ │ │ │ ├── 404$.tsx │ │ │ │ └── _theme.tsx │ │ │ │ ├── tsconfig.json │ │ │ │ └── vite.demos.ts │ │ ├── script │ │ │ └── copy.js │ │ └── tsconfig.json │ └── template-lib │ │ ├── README.md │ │ ├── _gitignore │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ ├── $.mdx │ │ ├── 404$.tsx │ │ └── _theme.tsx │ │ ├── src │ │ ├── Button │ │ │ ├── README.md │ │ │ ├── demos │ │ │ │ ├── demo1.tsx │ │ │ │ └── demo2.tsx │ │ │ ├── index.tsx │ │ │ └── style.module.css │ │ ├── Card │ │ │ ├── README.md │ │ │ ├── demos │ │ │ │ ├── demo1.tsx │ │ │ │ └── demo2.tsx │ │ │ ├── index.tsx │ │ │ └── style.module.css │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts ├── examples │ └── intro │ │ ├── components │ │ ├── Component.tsx │ │ ├── Layout.tsx │ │ └── Model.tsx │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ ├── _app.tsx │ │ ├── index.tsx │ │ └── ruby │ │ │ └── [slug].tsx │ │ ├── styles │ │ └── main.css │ │ ├── tsconfig.json │ │ ├── vitext.config.ts │ │ └── windi.config.ts ├── playground │ ├── basic │ │ ├── __tests__ │ │ │ ├── async.spec.ts │ │ │ ├── basic.spec.ts │ │ │ ├── hmr.spec.ts │ │ │ └── navigation.spec.ts │ │ ├── components │ │ │ └── Component.tsx │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ ├── all │ │ │ │ └── [[...all]].tsx │ │ │ ├── developer │ │ │ │ └── [...developerId].tsx │ │ │ ├── index.tsx │ │ │ ├── page1.tsx │ │ │ └── users │ │ │ │ ├── [userId].tsx │ │ │ │ └── index.tsx │ │ ├── styles │ │ │ └── main.css │ │ ├── vitext.config.ts │ │ └── yarn-error.log │ ├── css │ │ ├── __tests__ │ │ │ └── basic.spec.ts │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ ├── _app.tsx │ │ │ └── index.tsx │ │ ├── postcss.config.js │ │ ├── styles │ │ │ ├── main.css │ │ │ └── main.module.css │ │ ├── tailwind.config.js │ │ ├── vitext.config.ts │ │ └── yarn-error.log │ ├── custom-document-app │ │ ├── __tests__ │ │ │ └── basic.spec.ts │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ └── index.tsx │ │ ├── vitext.config.ts │ │ └── yarn-error.log │ ├── package.json │ ├── shims.d.ts │ ├── ssg-basic │ │ ├── __tests__ │ │ │ └── basic.spec.ts │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ ├── [slug].tsx │ │ │ └── users │ │ │ │ └── [slug].tsx │ │ ├── vitext.config.ts │ │ └── yarn-error.log │ ├── ssr-basic │ │ ├── __tests__ │ │ │ └── basic.spec.ts │ │ ├── declare.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pages │ │ │ └── index.tsx │ │ ├── vitext.config.ts │ │ └── yarn-error.log │ ├── testEnv.d.ts │ ├── testUtils.ts │ └── tsconfig.json └── vitext │ ├── .gitignore │ ├── .npmignore │ ├── bin │ └── vitext.js │ ├── package.json │ ├── react-shim.js │ ├── rollup.config.js │ ├── src │ ├── client │ │ ├── declarations.d.ts │ │ ├── main.tsx │ │ └── tsconfig.json │ ├── node │ │ ├── build.ts │ │ ├── cli.ts │ │ ├── components │ │ │ ├── Head.tsx │ │ │ ├── _app.tsx │ │ │ └── _document.tsx │ │ ├── constants.ts │ │ ├── middlewares │ │ │ └── page.ts │ │ ├── plugin.ts │ │ ├── preview.ts │ │ ├── proxy.ts │ │ ├── route │ │ │ ├── export.ts │ │ │ ├── fetch.ts │ │ │ ├── pages.ts │ │ │ └── render.tsx │ │ ├── server.ts │ │ ├── tsconfig.json │ │ ├── types.ts │ │ └── utils.ts │ └── react │ │ ├── dynamic.tsx │ │ ├── index.tsx │ │ ├── loadable.d.ts │ │ └── loadable.js │ ├── tsconfig.json │ └── yarn-error.log ├── prettier.config.js ├── scripts ├── jestEnv.js ├── jestGlobalSetup.js ├── jestGlobalTeardown.js ├── jestPerTestSetup.ts └── release.js ├── tsconfig.json ├── workspace.code-workspace └── yarn.lock /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/vitext"], 3 | "sandboxes": ["vanilla"], 4 | "node": "14" 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const { defineConfig } = require('eslint-define-config'); 3 | 4 | module.exports = defineConfig({ 5 | root: true, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:node/recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | ], 11 | parser: '@typescript-eslint/parser', 12 | parserOptions: { 13 | sourceType: 'module', 14 | ecmaVersion: 2020, 15 | }, 16 | rules: { 17 | '@typescript-eslint/explicit-function-return-type': 'off', 18 | '@typescript-eslint/explicit-module-boundary-types': 'off', 19 | eqeqeq: ['warn', 'always', { null: 'never' }], 20 | 'no-debugger': ['error'], 21 | 'no-empty': ['warn', { allowEmptyCatch: true }], 22 | 'no-process-exit': 'off', 23 | 'no-useless-escape': 'off', 24 | 'prefer-const': [ 25 | 'warn', 26 | { 27 | destructuring: 'all', 28 | }, 29 | ], 30 | 31 | 'node/no-missing-import': [ 32 | 'error', 33 | { 34 | allowModules: ['types', 'estree', 'testUtils', 'stylus'], 35 | tryExtensions: ['.ts', '.js', '.jsx', '.tsx', '.d.ts'], 36 | }, 37 | ], 38 | 'node/no-missing-require': [ 39 | 'error', 40 | { 41 | // for try-catching yarn pnp 42 | allowModules: ['pnpapi'], 43 | tryExtensions: ['.ts', '.js', '.jsx', '.tsx', '.d.ts'], 44 | }, 45 | ], 46 | 'node/no-restricted-require': [ 47 | 'error', 48 | Object.keys( 49 | require('./packages/vitext/package.json').devDependencies 50 | ).map((d) => ({ 51 | name: d, 52 | message: 53 | `devDependencies can only be imported using ESM syntax so ` + 54 | `that they are included in the rollup bundle. If you are trying to ` + 55 | `lazy load a dependency, use (await import('dependency')).default instead.`, 56 | })), 57 | ], 58 | 'node/no-extraneous-import': [ 59 | 'error', 60 | { 61 | allowModules: ['vite', 'less', 'sass'], 62 | }, 63 | ], 64 | 'node/no-extraneous-require': [ 65 | 'error', 66 | { 67 | allowModules: ['vite'], 68 | }, 69 | ], 70 | 'node/no-deprecated-api': 'off', 71 | 'node/no-unpublished-import': 'off', 72 | 'node/no-unpublished-require': 'off', 73 | 'node/no-unsupported-features/es-syntax': 'off', 74 | 75 | '@typescript-eslint/ban-ts-comment': 'off', // TODO: we should turn this on in a new PR 76 | '@typescript-eslint/ban-types': 'off', // TODO: we should turn this on in a new PR 77 | '@typescript-eslint/no-empty-function': [ 78 | 'error', 79 | { allow: ['arrowFunctions'] }, 80 | ], 81 | '@typescript-eslint/no-empty-interface': 'off', 82 | '@typescript-eslint/no-explicit-any': 'off', // maybe we should turn this on in a new PR 83 | '@typescript-eslint/no-extra-semi': 'off', // conflicts with prettier 84 | '@typescript-eslint/no-inferrable-types': 'off', 85 | '@typescript-eslint/no-non-null-assertion': 'off', // maybe we should turn this on in a new PR 86 | '@typescript-eslint/no-unused-vars': 'off', // maybe we should turn this on in a new PR 87 | '@typescript-eslint/no-var-requires': 'off', 88 | }, 89 | overrides: [ 90 | { 91 | files: ['packages/vitext/src/node/**'], 92 | rules: { 93 | 'no-console': ['error'], 94 | }, 95 | }, 96 | { 97 | files: ['packages/playground/**'], 98 | rules: { 99 | 'node/no-extraneous-import': 'off', 100 | 'node/no-extraneous-require': 'off', 101 | }, 102 | }, 103 | { 104 | files: ['packages/create-vitext/template-*/**'], 105 | rules: { 106 | 'node/no-missing-import': 'off', 107 | }, 108 | }, 109 | { 110 | files: ['*.js'], 111 | rules: { 112 | '@typescript-eslint/explicit-module-boundary-types': 'off', 113 | }, 114 | }, 115 | { 116 | files: ['*.d.ts'], 117 | rules: { 118 | '@typescript-eslint/triple-slash-reference': 'off', 119 | }, 120 | }, 121 | ], 122 | }); 123 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | env: 4 | NODE_OPTIONS: --max-old-space-size=6144 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | pull_request: 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | node_version: [12, 14, 16] 19 | include: 20 | - os: macos-latest 21 | node_version: 14 22 | - os: windows-latest 23 | node_version: 14 24 | fail-fast: false 25 | 26 | name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}" 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | 31 | - name: Set node version to ${{ matrix.node_version }} 32 | uses: actions/setup-node@v2 33 | with: 34 | node-version: ${{ matrix.node_version }} 35 | 36 | - name: Get yarn cache directory 37 | id: yarn-cache 38 | run: echo "::set-output name=dir::$(yarn cache dir)" 39 | 40 | - name: Set dependencies cache 41 | uses: actions/cache@v2 42 | with: 43 | path: ${{ steps.yarn-cache.outputs.dir }} 44 | key: ${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('yarn.lock') }} 45 | restore-keys: | 46 | ${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('yarn.lock') }} 47 | ${{ runner.os }}-${{ matrix.node_version }}- 48 | 49 | - name: Versions 50 | run: yarn versions 51 | 52 | - name: Install dependencies 53 | run: yarn install --frozen-lockfile 54 | 55 | - name: Build vitext 56 | run: yarn build 57 | 58 | - name: Test serve 59 | run: yarn test-serve --runInBand 60 | 61 | - name: Test build 62 | run: yarn test-build --runInBand 63 | 64 | lint: 65 | runs-on: ubuntu-latest 66 | name: "Lint: node-14, ubuntu-latest" 67 | steps: 68 | - uses: actions/checkout@v2 69 | with: 70 | fetch-depth: 0 71 | 72 | - name: Set node version to 14 73 | uses: actions/setup-node@v2 74 | with: 75 | node-version: 14 76 | 77 | - name: Set dependencies cache 78 | uses: actions/cache@v2 79 | with: 80 | path: ~/.cache/yarn 81 | key: lint-dependencies-${{ hashFiles('yarn.lock') }} 82 | restore-keys: | 83 | lint-dependencies-${{ hashFiles('yarn.lock') }} 84 | lint-dependencies- 85 | 86 | - name: Prepare 87 | run: | 88 | yarn install --frozen-lockfile 89 | 90 | - name: Lint 91 | run: yarn lint 92 | 93 | - name: Checkout 94 | uses: actions/checkout@v2 95 | - name: Semantic Release 96 | uses: cycjimmy/semantic-release-action@v2 97 | env: 98 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 99 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 100 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release npm package 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@master 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "14.x" 17 | - run: yarn install --frozen-lockfile 18 | - run: yarn build 19 | - run: yarn workspace vitext run semantic-release 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | dist 4 | tmp 5 | temp 6 | .vscode 7 | .yarn 8 | workspace.code-workspace 9 | TODO.md 10 | 11 | packages/vitext/react.d.ts 12 | packages/vitext/src/node/error.ts 13 | .vimspector.json 14 | core -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | ## pnpm 4 | 5 | This project uses pnpm to manage monorepo. You should run `pnpm i` after cloning this repo. 6 | 7 | ## Tests 8 | 9 | The test setup is copied from [vite](https://github.com/vitejs/vite/blob/f6b58a0f535b1c26f9c1dfda74c28c685402c3c9/jest.config.js#L1). Fixtures and test cases is under `packages/playground`. 10 | 11 | > There must be no more than one `.spec.ts` file for each fixture. Otherwise it will cause Error like `Error: EEXIST: file already exists, mkdir '/home/csr/vitext/temp/basic'`. There is some flaws with current test setup (which is copied from vite's repo). 12 | 13 | ## Run playgrounds 14 | 15 | ```sh 16 | cd packages/playground/basic/ # or other playgrounds 17 | npm run dev 18 | ``` 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 M. Bagher Abiat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vitext ⚡🚀 2 | 3 | [](https://discord.gg/Rhg9cEghMF) 4 | 5 | > The Next.js like React framework for better User & Developer experience 6 | 7 | - 💡 Instant Server Start 8 | - 💥 Suspense support 9 | - ⚫ Next.js like API 10 | - 📦 Optimized Build 11 | - 💎 Build & Export on fly 12 | - 🚀 Lightning SSG/SSR 13 | - ⚡ Fast HMR 14 | - 🔑 Vite & Rollup Compatible 15 | 16 | https://user-images.githubusercontent.com/37929992/128530290-41165a31-29a5-4108-825b-843a09059deb.mp4 17 | ``` 18 | npm install vitext 19 | ``` 20 | 21 | Vitext (Vite + Next) is a lightning fast SSG/SSR tool that lets you develop better and quicker front-end apps. It consists of these major parts: 22 | 23 | ### 💡 Instant Server Start 24 | The development server uses native ES modules, So you're going to have your React app server-rendered and client rendered very fast, under a half a second for me. 25 | 26 | ### 💥 Suspense support 27 | Vitext supports React Suspense & Lazy out of the box. 28 | ```ts 29 | import { lazy, Suspense } from 'react'; 30 | 31 | const Component = lazy(() => import('../components/Component')); 32 | const Loading = () =>
Loading the Component
; 33 | 34 | const App = () => { 35 | return ( 36 |page 2. This is a page inside a dir.
10 | } 11 | 12 | export default Page 13 | -------------------------------------------------------------------------------- /packages/create-project/template-app/pages/dir/page3/box.module.css: -------------------------------------------------------------------------------- 1 | .box { 2 | border: 1px solid red; 3 | } 4 | -------------------------------------------------------------------------------- /packages/create-project/template-app/pages/dir/page3/box.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import s from './box.module.css' 3 | 4 | const Box = () => { 5 | returnThis is page1. This is a page defined with React component.
10 | } 11 | 12 | export default Page 13 | -------------------------------------------------------------------------------- /packages/create-project/template-app/pages/users/[userId]/index$.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @title dynamic route page 3 | */ 4 | 5 | import React from 'react' 6 | import { useParams } from 'react-router-dom' 7 | 8 | const IndexPage = () => { 9 | const { userId } = useParams<{ userId: string }>() 10 | return ( 11 |You can put an introduction here.
12 |Loading the Ruby 💎
; 8 | 9 | const IndexPage = () => { 10 | const ref = useRef(); 11 | const [number, setNumber] = useState(0); 12 | return ( 13 |⚡🚀
15 |16 | 22 | Vitext 23 | 24 |
25 | 26 |The Next.js like React framework for Speed
27 | 28 |42 | How many rubies do you want? 43 |
44 | {number} 45 |Loading the Ruby 💎
; 10 | 11 | const Ruby = ({ id }) => { 12 | const ref = useRef(); 13 | 14 | return ( 15 |Dynamicly loaded using React.lazy & Suspense
43 | 44 |hello
7 |= { 12 | paths: Array<{ params: P }>; 13 | }; 14 | 15 | export type GetPaths
= () =>
16 | | Promise ;
18 |
19 | export type GetPropsContext = { props: P; revalidate?: number | boolean };
28 | type NotFound = { notFound?: true };
29 |
30 | export type GetPropsResult = JustProps & NotFound;
31 |
32 | export type GetProps<
33 | P extends { [key: string]: any } = { [key: string]: any },
34 | Q extends ParsedUrlQuery = ParsedUrlQuery
35 | > = (context: GetPropsContext = () => Promise ;
32 |
33 | export type LoadableOptions = Omit ;
35 | loading?: ({
36 | error,
37 | isLoading,
38 | pastDelay,
39 | }: {
40 | error?: Error | null;
41 | isLoading?: boolean;
42 | pastDelay?: boolean;
43 | retry?: () => void;
44 | timedOut?: boolean;
45 | }) => JSX.Element | null;
46 | };
47 |
48 | export type DynamicOptions = LoadableOptions ;
49 |
50 | export type LoadableFn = (opts: LoadableOptions ) => P;
51 |
52 | export type LoadableComponent = P;
53 |
54 | type Props = P & {
55 | fallback: string | LoadableOptions (
58 | loadableOptions: LoadableOptions (
96 | loader: Loader >(opts: any): React.ComponentType ;
60 | Map >(
61 | opts: any
62 | ): React.ComponentType ;
63 | preloadAll(): Promise = {
20 | req?: IncomingMessage;
21 | res?: ServerResponse;
22 | params?: Q;
23 | query: ParsedUrlQuery;
24 | isExporting: boolean;
25 | };
26 |
27 | type JustProps
) => Promise