├── website ├── static │ └── img │ │ ├── logo-og.png │ │ ├── oss_logo.png │ │ ├── update.png │ │ ├── favicon │ │ └── favicon.ico │ │ ├── logo.svg │ │ └── docusaurus.svg ├── sidebars.json ├── .gitignore ├── README.md ├── package.json ├── src │ ├── css │ │ └── custom.css │ ├── pages │ │ ├── styles.module.css │ │ └── index.js │ └── theme │ │ └── DocItem │ │ ├── styles.module.css │ │ └── index.js └── docusaurus.config.js ├── .github └── workflows │ └── deploy.yml └── docs ├── getting-started.md ├── directory-structure.md ├── getInitialProps.md ├── documentation-intro.md ├── config.md └── api.md /website/static/img/logo-og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IFmiss/shuvijs.org/master/website/static/img/logo-og.png -------------------------------------------------------------------------------- /website/static/img/oss_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IFmiss/shuvijs.org/master/website/static/img/oss_logo.png -------------------------------------------------------------------------------- /website/static/img/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IFmiss/shuvijs.org/master/website/static/img/update.png -------------------------------------------------------------------------------- /website/static/img/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IFmiss/shuvijs.org/master/website/static/img/favicon/favicon.ico -------------------------------------------------------------------------------- /website/sidebars.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": { 3 | "介绍": [ 4 | "getting-started" 5 | ], 6 | "基础": [ 7 | "directory-structure" 8 | ], 9 | "获取数据": [ 10 | "getInitialProps" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # production 5 | /build 6 | 7 | # generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using Docusaurus 2, a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```shell 8 | yarn 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```shell 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```shell 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v2 12 | with: 13 | persist-credentials: false 14 | 15 | - name: Install and Build 🔧 16 | run: | 17 | cd website 18 | yarn 19 | npm run-script build 20 | 21 | - name: Deploy 🚀 22 | uses: JamesIves/github-pages-deploy-action@releases/v3 23 | with: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | BRANCH: gh-pages 26 | FOLDER: website/build 27 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "docusaurus start", 4 | "build": "docusaurus build", 5 | "swizzle": "docusaurus swizzle", 6 | "deploy": "docusaurus deploy" 7 | }, 8 | "dependencies": { 9 | "@docusaurus/core": "^2.0.0-alpha.39", 10 | "@docusaurus/preset-classic": "^2.0.0-alpha.39", 11 | "classnames": "^2.2.6", 12 | "react": "^16.12.0", 13 | "react-dom": "^16.12.0" 14 | }, 15 | "browserslist": { 16 | "production": [ 17 | ">0.2%", 18 | "not dead", 19 | "not op_mini all" 20 | ], 21 | "development": [ 22 | "last 1 chrome version", 23 | "last 1 firefox version", 24 | "last 1 safari version" 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: getting-started 3 | title: 快速上手 4 | --- 5 | 6 | ## 介绍 7 | 8 | shuvi 是前端应用开发的解决方案,整合了现代工具链,专注于提升开发体验和效率。 9 | 10 | ## 使用 11 | 12 | 创建项目 13 | 14 | ```sh 15 | mkdir my-app & cd my-app 16 | npm init -y 17 | ``` 18 | 19 | 安装 shuvi 20 | 21 | ```sh 22 | npm install shuvi@beta 23 | ``` 24 | 25 | 创建 `src/pages` 目录, 并生成一个 hello world 页面 26 | ```sh 27 | mkdir -p src/pages 28 | cat <> /src/pages/index.js 29 | export default () =>
hello, world
30 | EOF 31 | ``` 32 | 33 | 在 `package.json` 种添加脚本 34 | ```json 35 | { 36 | "scripts": { 37 | "dev": "shuvi dev", 38 | "build": "shuvi build", 39 | "serve": "shuvi serve" 40 | } 41 | } 42 | ``` 43 | 44 | 启动项目 45 | ```sh 46 | npm run dev 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/directory-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: directory-structure 3 | title: 目录结构 4 | --- 5 | 6 | shuvi 项目的目录结构如下: 7 | 8 | ``` 9 | . 10 | ├── .shuvi 11 | ├── shuvi.config.js 12 | ├── public 13 | ├── dist 14 | └── src 15 | ├── pages 16 | └── index.jsx 17 | └── app.js 18 | └── document.js 19 | ``` 20 | 21 | ## 根目录 22 | 23 | ### .shuvi 目录 24 | 25 | 临时文件目录,比如入口文件、路由等,都会被临时生成到这里。**不要提交 `.shuvi` 目录到 git 仓库,他们会在 `shuvi dev` 和 `shuvi build` 时被删除并重新生成。** 26 | 27 | ### shuvi.config.js 28 | 29 | 配置文件,可以修改 shuvi 选项和配置插件。 30 | 31 | ### dist 目录 32 | 33 | 默认的构建输出目录。 34 | 35 | ### public 目录 36 | 37 | 此目录下所有文件会被 copy 到输出路径。 38 | 39 | ## `/src` 目录 40 | 41 | ### pages 目录 42 | 43 | 约定式路由目录。 44 | 45 | ### app.js 46 | 47 | 根组件,所有路由的渲染都会经过这里。 48 | 49 | ### document.js 50 | 51 | 控制文档的内容。 52 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --ifm-color-primary: #09d3ac; 3 | --ifm-color-primary-dark: rgb(8, 190, 155); 4 | --ifm-color-primary-darker: rgb(8, 179, 146); 5 | --ifm-color-primary-darkest: rgb(6, 148, 120); 6 | --ifm-color-primary-light: rgb(46, 218, 184); 7 | --ifm-color-primary-lighter: rgb(83, 224, 197); 8 | --ifm-color-primary-lightest: rgb(132, 233, 214); 9 | } 10 | 11 | @media screen and (max-width: 996px) { 12 | :root { 13 | --ifm-font-size-base: 13px; 14 | } 15 | } 16 | 17 | @media screen and (min-width: 997px) { 18 | :root { 19 | --ifm-font-size-base: 15px; 20 | } 21 | } 22 | 23 | .docusaurus-highlight-code-line { 24 | background-color: rgb(72, 77, 91); 25 | display: block; 26 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 27 | padding: 0 var(--ifm-pre-padding); 28 | } 29 | 30 | .navbar .navbar__brand > strong { 31 | flex-shrink: 0; 32 | max-width: 100%; 33 | } 34 | -------------------------------------------------------------------------------- /docs/getInitialProps.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: getInitialProps 3 | title: 数据获取 4 | --- 5 | 6 | ## 页面级数据获取 7 | 8 | 每个页面可能有单独的数据预获取逻辑,这里我们会获取页面组件上的 `getInitialProps` 静态方法,执行后将结果注入到该页面组件的 `props` 中,例如: 9 | 10 | ```jsx 11 | function Page({ title }) { 12 | return
{title}
; 13 | } 14 | 15 | Page.getInitialProps = async ctx => { 16 | return new Promise(resolve => { 17 | setTimeout( 18 | () => 19 | resolve({ 20 | title: "Hello World" 21 | }), 22 | 1e3 23 | ); 24 | }); 25 | }; 26 | 27 | export default Page; 28 | ``` 29 | 30 | ## `context` 对象 31 | 32 | `getInitialProps` 接受一个 `context` 对象, 包含如下属性: 33 | 34 | - `isServer` - 是否运行在服务端 35 | - `pathname` - 当前 url 的路径 36 | - `query` - 路由路径参数 37 | - `params` - url 请求参数 38 | - `redirect` - 重定向函数 39 | - `redirect('/target')` 40 | - `redirect(301, '/target')` 41 | - `appContext` - 应用上下文对象,伴随者整个应用的生命周期 42 | - `req` - HTTP request object (server only) 43 | -------------------------------------------------------------------------------- /docs/documentation-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: documentation-intro 3 | title: About the Documentation 4 | sidebar_label: About Docs 5 | --- 6 | 7 | Welcome to the Create React App documentation! 8 | 9 | ## Navigation 10 | 11 | You can find different topics in the table of contents. On desktop, you should see it in the left sidebar. On mobile, you should see it after pressing an icon with arrows in the top left corner. 12 | 13 | ## Looking for React Docs? 14 | 15 | The documentation for React itself is located on a separate website: **[reactjs.org](https://reactjs.org/)**. 16 | 17 | This website is only about Create React App. 18 | 19 | ## Something Missing? 20 | 21 | If you have ideas for more “How To” recipes that should be on this page, [let us know](https://github.com/facebook/create-react-app/issues) or [contribute some!](https://github.com/facebook/create-react-app/tree/master/docusaurus/docs) 22 | 23 | ## Feedback 24 | 25 | We are always open to [your feedback](https://github.com/facebook/create-react-app/issues). 26 | -------------------------------------------------------------------------------- /website/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 2.5rem 0; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | .heroBannerLogo { 16 | max-width: 170px; 17 | max-height: 170px; 18 | } 19 | 20 | @media screen and (max-width: 966px) { 21 | .heroBanner { 22 | padding: 2rem; 23 | } 24 | } 25 | 26 | .getStarted { 27 | display: flex; 28 | align-items: center; 29 | justify-content: center; 30 | } 31 | 32 | .features { 33 | display: flex; 34 | align-items: center; 35 | padding: 4rem 0; 36 | width: 100%; 37 | } 38 | 39 | .featureImage { 40 | margin: 0 auto; 41 | } 42 | 43 | .gettingStartedSection { 44 | background-color: #f7f7f7; 45 | } 46 | 47 | html[data-theme='dark'] .gettingStartedSection { 48 | background-color: #33363b; 49 | } 50 | -------------------------------------------------------------------------------- /website/src/theme/DocItem/styles.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | .docTitle { 9 | font-size: 2.5rem; 10 | margin-bottom: 2.5rem; 11 | } 12 | 13 | @media only screen and (max-width: 996px) { 14 | .docTitle { 15 | font-size: 1.6rem; 16 | margin-bottom: 1.6rem; 17 | } 18 | } 19 | 20 | .docItemContainer { 21 | margin: 0 auto; 22 | padding: 0 0.5rem; 23 | } 24 | 25 | .tableOfContents { 26 | display: inherit; 27 | max-height: calc(100vh - (var(--ifm-navbar-height) + 2rem)); 28 | overflow-y: auto; 29 | position: sticky; 30 | top: calc(var(--ifm-navbar-height) + 2rem); 31 | } 32 | 33 | .tableOfContents::-webkit-scrollbar { 34 | width: 7px; 35 | } 36 | 37 | .tableOfContents::-webkit-scrollbar-track { 38 | background: #f1f1f1; 39 | border-radius: 10px; 40 | } 41 | 42 | .tableOfContents::-webkit-scrollbar-thumb { 43 | background: #888; 44 | border-radius: 10px; 45 | } 46 | 47 | .tableOfContents::-webkit-scrollbar-thumb:hover { 48 | background: #555; 49 | } 50 | 51 | @media only screen and (max-width: 996px) { 52 | .tableOfContents { 53 | display: none; 54 | } 55 | 56 | .docItemContainer { 57 | padding: 0 0.3rem; 58 | } 59 | } 60 | 61 | .docLastUpdatedAt { 62 | font-weight: bold; 63 | } 64 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const siteConfig = { 9 | title: 'Shuvijs', 10 | tagline: 'Shuvijs', 11 | url: 'https://shuvijs.github.io/shuvijs.org/', 12 | baseUrl: '/shuvijs.org/', 13 | projectName: 'shuvijs-doc', 14 | organizationName: 'Shuvijs', 15 | favicon: 'img/favicon/favicon.ico', 16 | presets: [ 17 | [ 18 | '@docusaurus/preset-classic', 19 | { 20 | docs: { 21 | path: '../docs', 22 | sidebarPath: require.resolve('./sidebars.json'), 23 | editUrl: 'https://github.com/shuvijs/shuvijs.org/tree/master/website/', 24 | // showLastUpdateAuthor: true, 25 | // showLastUpdateTime: true, 26 | }, 27 | theme: { 28 | customCss: require.resolve('./src/css/custom.css'), 29 | }, 30 | }, 31 | ], 32 | ], 33 | themeConfig: { 34 | image: 'img/logo-og.png', 35 | algolia: { 36 | apiKey: 'ddf5199f80099ebf2895567663218470', 37 | indexName: 'shuvijs', 38 | }, 39 | sidebarCollapsible: false, 40 | navbar: { 41 | title: 'Shuvijs', 42 | logo: { 43 | alt: 'Shuvijs', 44 | src: 'img/logo.svg', 45 | }, 46 | links: [ 47 | { to: 'docs/getting-started', label: '文档', position: 'right' }, 48 | { to: 'docs/config', label: '配置', position: 'right' }, 49 | {to: 'docs/api', label: 'API', position: 'right'}, 50 | { 51 | href: 'https://github.com/shuvijs/shuvi', 52 | label: 'GitHub', 53 | position: 'right', 54 | }, 55 | ], 56 | }, 57 | footer: { 58 | style: 'dark', 59 | links: [ 60 | { 61 | title: 'Docs', 62 | items: [ 63 | { 64 | label: 'Get Started', 65 | to: 'docs/getting-started', 66 | }, 67 | ], 68 | }, 69 | { 70 | title: 'Social', 71 | items: [ 72 | { 73 | label: 'GitHub', 74 | href: 'https://github.com/shuvijs/shuvi', 75 | }, 76 | ], 77 | }, 78 | ], 79 | copyright: `Copyright © ${new Date().getFullYear()} Shuvijs`, 80 | }, 81 | }, 82 | } 83 | 84 | module.exports = siteConfig 85 | -------------------------------------------------------------------------------- /website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from "react"; 9 | import Link from "@docusaurus/Link"; 10 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; 11 | import useBaseUrl from "@docusaurus/useBaseUrl"; 12 | 13 | import Layout from "@theme/Layout"; 14 | import CodeBlock from "@theme/CodeBlock"; 15 | 16 | import classnames from "classnames"; 17 | 18 | import styles from "./styles.module.css"; 19 | 20 | const features = [ 21 | { 22 | title: "注重体验", 23 | content: 24 | "以开发者为中心,强调开发体验,注重开发效率。" 25 | }, 26 | { 27 | title: "开箱即用", 28 | content: 29 | "仅需一个依赖,即可拥有一个深度优化的现代前端应用程序。" 30 | }, 31 | { 32 | title: "丰富的扩展性", 33 | content: 34 | "提供了丰富的接口,可以通过插件满足各种不同的功能和需求。" 35 | }, 36 | ]; 37 | 38 | function Home() { 39 | const context = useDocusaurusContext(); 40 | const { siteConfig = {} } = context; 41 | 42 | return ( 43 | 47 |
48 |
49 | 53 |

{siteConfig.title}

54 |

{siteConfig.tagline}

55 |
56 | 60 | 开始使用 61 | 62 |
63 |
64 |
65 | {features && features.length && ( 66 |
67 |
68 |
69 | {features.map(({ title, content }, idx) => ( 70 |
74 |

{title}

75 |

{content}

76 |
77 | ))} 78 |
79 |
80 |
81 | )} 82 |
83 | ); 84 | } 85 | 86 | export default Home; 87 | -------------------------------------------------------------------------------- /docs/config.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: config 3 | title: 配置 4 | --- 5 | 6 | ## env 7 | 8 | - Type: `object` 9 | - Default: `{}` 10 | 11 | 配置打包时替换的环境变量值。例如: 12 | ```js 13 | module.exports = { 14 | env: { 15 | customKey: 'my-value', 16 | } 17 | } 18 | ``` 19 | 20 | 在代码种可通过 `process.env.customKey` 访问: 21 | 22 | ```jsx 23 | function Page() { 24 | return

The value of customKey is: {process.env.customKey}

25 | } 26 | 27 | export default Page 28 | ``` 29 | 30 | ## outputPath 31 | 32 | - Type: `string` 33 | - Default: `dist` 34 | 35 | 指定输出路径。 36 | 37 | ## publicPath 38 | 39 | - Type: `string` 40 | - Default: `/_shuvi` 41 | 42 | 配置静态资源的 `publicPath`。此路径会被添加到静态文件的访问路径前。 43 | 44 | ## plugins 45 | 46 | - Type: `Plugin[]` 47 | - Default: `[]` 48 | 49 | 配置插件。 50 | 51 | ```js 52 | module.exports = { 53 | plugins: [ 54 | // npm 依赖 55 | 'plugin', 56 | // 相对路径 57 | './plugin', 58 | // 绝对路径 59 | `${__dirname}/plugin.js`, 60 | // 配置选项 61 | ['plugin', { optionA: 'valueA' }], 62 | // inline plugin 63 | api => { 64 | // do something with api 65 | } 66 | ], 67 | }; 68 | ``` 69 | 70 | ## proxy 71 | 72 | - Type: `object` 73 | - Default: `undefined` 74 | 75 | 配置代理。 76 | 77 | ```js 78 | module.exports = { 79 | proxy: { 80 | '/api': { 81 | 'target': 'http://api.host.com/', 82 | 'pathRewrite': { '^/api' : '' }, 83 | }, 84 | }, 85 | ``` 86 | 87 | ## runtimeConfig 88 | 89 | 设置运行时变量。示例: 90 | ```js 91 | module.exports = { 92 | runtimeConfig: { 93 | staticFolder: '/static', 94 | } 95 | } 96 | ``` 97 | 98 | 通过如下方式访问: 99 | ```js 100 | import { getRuntimeConfig } from '@shuvi/app' 101 | 102 | const { staticFolder } = getRuntimeConfig() 103 | // Will be available on both server-side and client-side 104 | console.log(publicRuntimeConfig.staticFolder) 105 | 106 | export default function MyImage() { 107 | return ( 108 |
109 | logo 110 |
111 | ) 112 | } 113 | ``` 114 | 115 | ## rootDir 116 | 117 | - Type: `string` 118 | - Default: `process.cwd()` 119 | 120 | 设置应用程序的根目录。 121 | 122 | ## router 123 | 124 | - Type: `object` 125 | - Default: `{ history: 'auto' }` 126 | 127 | ```js 128 | module.exports = { 129 | router: { 130 | hisotry: 'auto', // 'auto' | 'browser' | 'hash' 131 | }, 132 | }; 133 | ``` 134 | * 当 `hisotry` 为 `auto` 时,启用了 ssr 则为 `browser`,反之则为 `hash`。 135 | 136 | 137 | ## routes 138 | 139 | - Type: `Route[]` 140 | - Default: `undefined` 141 | 142 | 配置和 `react-router` 基本一致。 143 | 144 | ```js 145 | module.exports = { 146 | routes: [ 147 | { 148 | path: '/', 149 | component: 'index', 150 | routes: [ 151 | { path: '/hello', redirect: '/path/to/hello' }, 152 | { path: '/user', component: 'user' }, 153 | ], 154 | }, 155 | ], 156 | }; 157 | ``` 158 | 159 | 相对路径会基于 `src/pages` 目录解析。 160 | 161 | ## ssr 162 | 163 | - Type: `boolean` 164 | - Default: `true` 165 | 166 | 配置是否开启服务端渲染。 167 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: api 3 | title: API 4 | --- 5 | 6 | ## 基本 API 7 | 8 | ### head 9 | 10 | 为文档的 `head` 添加子元素: 11 | 12 | ```js 13 | import { Head } from "@shuvi/app"; 14 | 15 | function IndexPage() { 16 | return ( 17 |
18 | 19 | My page title 20 | 21 | 22 |

Hello world!

23 |
24 | ); 25 | } 26 | 27 | export default IndexPage; 28 | ``` 29 | 30 | ### dynamic 31 | 32 | 动态加载组件。 33 | 34 | **常见使用场景**:组件体积太大,不适合直接计入 bundle 中,以免影响首屏加载速度。例如:某组件 HugeA 包含巨大的实现 / 依赖了巨大的三方库,且该组件 HugeA 的使用不在首屏显示范围内,可被单独拆出。这时候,`dynamic` 就该上场了。 35 | 36 | **为什么使用 `dynamic`**:封装了使用一个异步组件需要做的状态维护工作,开发者可以更专注于自己的业务组件开发,而不必关心 code spliting、async module loading 等等技术细节。 37 | 38 | 通常搭配 [动态 import 语法](https://github.com/tc39/proposal-dynamic-import) 使用。 39 | 40 | **使用异步组件** 41 | 42 | ```js 43 | import React from "react"; 44 | const AsyncComponent = dynamic(() => import("./Component")); 45 | 46 | // 像使用普通组件一样即可 47 | // dynamic 为你做: 48 | // 1. 异步加载该模块的 bundle 49 | // 2. 加载期间 显示 loading(可定制) 50 | // 3. 异步组件加载完毕后,显示异步组件 51 | export default () => { 52 | return ; 53 | }; 54 | ``` 55 | 56 | **封装一个异步组件** 57 | 58 | ```js 59 | import { dynamic } from "@shuvi/app"; 60 | 61 | export default dynamic(async () => { 62 | // 这里的注释 webpackChunkName 可以指导 webpack 将该组件 HugeA 以这个名字单独拆出去 63 | const { default: HugeA } = await import( 64 | /* webpackChunkName: "external_A" */ "./HugeA" 65 | ); 66 | return HugeA; 67 | }); 68 | ``` 69 | 70 | ## 路由 71 | 72 | ### router 73 | 74 | 可用于获取当前路由信息, 75 | 76 | ```js 77 | import { router } from "@shuvi/app"; 78 | ``` 79 | 80 | 可用于路由跳转, 81 | 82 | ```js 83 | import { router } from "@shuvi/app"; 84 | 85 | // 跳转到指定路由 86 | router.push("/list"); 87 | 88 | // 带参数跳转到指定路由 89 | router.push("/list?a=b"); 90 | router.push({ 91 | pathname: "/list", 92 | search: "?a=b" 93 | }); 94 | 95 | // 跳转到上一个路由 96 | history.goBack(); 97 | 98 | // 监听路由改变 99 | router.onChange(() => { 100 | window.ga("send", "pageview"); 101 | }); 102 | ``` 103 | 104 | ### Link 105 | 106 | 链接组件,例如: 107 | 108 | ```tsx 109 | import { Link } from "@shuvi/app"; 110 | 111 | export default () => { 112 | return ( 113 |
114 | {/* 点击跳转到指定 /about 路由 */} 115 | About 116 | 117 | {/* 点击跳转到指定 /courses 路由, 118 | 附带 query { sort: 'name' } 119 | */} 120 | Courses 121 | 122 | {/* 点击跳转到指定 /list 路由, 123 | 附带 query: { sort: 'name' } 124 | 附带 hash: 'the-hash' 125 | 附带 state: { fromDashboard: true } 126 | */} 127 | 135 | List 136 | 137 | 138 | {/* 点击跳转到指定 /profile 路由, 139 | 附带所有当前 location 上的参数 140 | */} 141 | { 143 | return { ...location, pathname: "/profile" }; 144 | }} 145 | /> 146 | 147 | {/* 点击跳转到指定 /courses 路由, 148 | 但会替换当前 history stack 中的记录 149 | */} 150 | 151 | 152 | {/* 153 | innerRef 允许你获取基础组件(这里应该就是 a 标签或者 null) 154 | */} 155 | { 158 | // `node` refers to the mounted DOM element 159 | // or null when unmounted 160 | }} 161 | /> 162 |
163 | ); 164 | }; 165 | ``` 166 | 167 | ### useHistory 168 | 169 | hooks,获取 `history` 对象 170 | 171 | ```tsx 172 | import { useHistory } from "@shuvi/app"; 173 | 174 | export default () => { 175 | const history = useHistory(); 176 | return ( 177 |
178 |
    179 |
  • history: {history.action}
  • 180 |
181 |
182 | ); 183 | }; 184 | ``` 185 | 186 | ### useLocation 187 | 188 | hooks,获取 `location` 对象 189 | 190 | ```tsx 191 | import { useLocation } from "@shuvi/app"; 192 | 193 | export default () => { 194 | const location = useLocation(); 195 | return ( 196 |
197 |
    198 |
  • location: {location.pathname}
  • 199 |
200 |
201 | ); 202 | }; 203 | ``` 204 | 205 | ### useParams 206 | 207 | hooks,获取 `params` 对象。 `params` 对象为动态路由(例如:`/users/:id`)里的参数键值对。 208 | 209 | ```tsx 210 | import { useParams } from "@shuvi/app"; 211 | 212 | export default () => { 213 | const params = useParams(); 214 | return ( 215 |
216 |
    217 |
  • params: {JSON.stringify(params)}
  • 218 |
219 |
220 | ); 221 | }; 222 | ``` 223 | 224 | ### useRouteMatch 225 | 226 | 获取当前路由的匹配信息。 227 | 228 | ```tsx 229 | import { useRouteMatch } from "@shuvi/app"; 230 | 231 | export default () => { 232 | const match = useRouteMatch(); 233 | return ( 234 |
235 |
    236 |
  • match: {JSON.stringify(match.params)}
  • 237 |
238 |
239 | ); 240 | }; 241 | ``` 242 | 243 | ## Nodejs API 244 | 245 | ```js 246 | // server.js 247 | const { createServer } = require("http"); 248 | const { parse } = require("url"); 249 | const shuvi = require("shuvi"); 250 | 251 | const dev = process.env.NODE_ENV !== "production"; 252 | const app = shuvi({ dev }); 253 | 254 | try { 255 | await app.listen(3000); 256 | console.log(`Ready on http://localhost:${port}`); 257 | } catch (err) { 258 | console.error(err); 259 | process.exit(1); 260 | } 261 | ``` 262 | -------------------------------------------------------------------------------- /website/src/theme/DocItem/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | 10 | import Head from '@docusaurus/Head'; 11 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 12 | import useBaseUrl from '@docusaurus/useBaseUrl'; 13 | import DocPaginator from '@theme/DocPaginator'; 14 | import useTOCHighlight from '@theme/hooks/useTOCHighlight'; 15 | 16 | import styles from './styles.module.css'; 17 | 18 | const LINK_CLASS_NAME = 'contents__link'; 19 | const ACTIVE_LINK_CLASS_NAME = 'contents__link--active'; 20 | const TOP_OFFSET = 100; 21 | 22 | function DocTOC({headings}) { 23 | useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET); 24 | return ( 25 |
26 |
27 | 28 |
29 |
30 | ); 31 | } 32 | 33 | /* eslint-disable jsx-a11y/control-has-associated-label */ 34 | function Headings({headings, isChild}) { 35 | if (!headings.length) return null; 36 | return ( 37 | 49 | ); 50 | } 51 | 52 | function DocItem(props) { 53 | const {siteConfig = {}} = useDocusaurusContext(); 54 | const {url: siteUrl} = siteConfig; 55 | const {content: DocContent} = props; 56 | const {metadata} = DocContent; 57 | const { 58 | description, 59 | title, 60 | permalink, 61 | image: metaImage, 62 | editUrl, 63 | lastUpdatedAt, 64 | lastUpdatedBy, 65 | keywords, 66 | version, 67 | } = metadata; 68 | const { 69 | frontMatter: { 70 | hide_title: hideTitle, 71 | hide_table_of_contents: hideTableOfContents, 72 | }, 73 | } = DocContent; 74 | 75 | const metaImageUrl = siteUrl + useBaseUrl(metaImage); 76 | 77 | return ( 78 | <> 79 | 80 | {title && {title}} 81 | {description && } 82 | {description && ( 83 | 84 | )} 85 | {keywords && keywords.length && ( 86 | 87 | )} 88 | {metaImage && } 89 | {metaImage && } 90 | {metaImage && ( 91 | 92 | )} 93 | {permalink && } 94 | 95 |
96 |
97 |
98 |
99 |
100 |
101 | {version && ( 102 | 105 | Version: {version} 106 | 107 | )} 108 | {!hideTitle && ( 109 |
110 |

{title}

111 |
112 | )} 113 | 114 |
115 | 116 |
117 |
118 | {(editUrl || lastUpdatedAt || lastUpdatedBy) && ( 119 |
184 | )} 185 |
186 | 187 |
188 |
189 |
190 | {!hideTableOfContents && DocContent.rightToc && ( 191 | 192 | )} 193 |
194 |
195 |
196 | 197 | ); 198 | } 199 | 200 | export default DocItem; 201 | -------------------------------------------------------------------------------- /website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/static/img/docusaurus.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------