diff --git a/.vscode/settings.json b/.vscode/settings.json index 0676d0c..54e9289 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,9 @@ "[javascript]": { "editor.formatOnSave": true }, + "[markdown]": { + "editor.formatOnSave": true + }, "editor.tabSize": 2, "editor.insertSpaces": true, "files.associations": { diff --git a/README-zh_CN.md b/README-zh_CN.md index 9720c4a..0e53483 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -14,18 +14,18 @@ npm i @unis/core @unis/dom ## Vite 开发 -```jsx +```shell npm i vite @unis/vite-preset -D ``` vite.config.js -```jsx -import { defineConfig } from "vite" -import { unisPreset } from "@unis/vite-preset" +```javascript +import { defineConfig } from "vite"; +import { unisPreset } from "@unis/vite-preset"; export default defineConfig({ - plugins: [unisPreset()] + plugins: [unisPreset()], }); ``` @@ -42,7 +42,7 @@ tsconfig.json index.html -```jsx +```javascript ... @@ -54,16 +54,12 @@ index.html index.tsx -```tsx +```javascript function App() { - return () => ( -
- hello -
- ) + return () =>
hello
; } -render(, document.querySelector('#root')) +render(, document.querySelector("#root")); ``` ## 用法 @@ -74,110 +70,100 @@ Unis 并不是 React 的复刻,而是保留了 React 使用体验的全新框 在 unis 中组件是一个高阶函数。 -```jsx -import { render } from '@unis/dom' +```javascript +import { render } from "@unis/dom"; const App = () => { - return () => ( // 返回一个函数 -
- hello world -
- ) -} + return () => ( + // 返回一个函数 +
hello world
+ ); +}; -render(, document.querySelector('#root')) +render(, document.querySelector("#root")); ``` ### 组件状态 Unis 中的 `useState` 用法和 React 相似,但是要注意的是 unis 中 `use` 系列方法,定义类型必须为 `let` ,因为 unis 使用了 Callback Reassign 编译策略,[@callback-reassign/rollup-plugin](https://github.com/anuoua/callback-reassign) 帮我们补全了 Callback Reassign 代码。 -```jsx -import { useState } from "@unis/core" +```javascript +import { useState } from "@unis/core"; const App = () => { - let [msg, setMsg] = useState('hello') + let [msg, setMsg] = useState("hello"); /** * Compile to: - * + * * let [msg, setMsg] = useState('hello', ([$0, $1]) => { msg = $0; setMsg = $1 }); */ - return () => ( -
{msg}
- ) -} + return () =>
{msg}
; +}; ``` ### Props Unis 直接使用 props 会无法获取最新值,所以 unis 提供了 useProps。 -```jsx -import { useProps } from "@unis/core" +```javascript +import { useProps } from "@unis/core"; const App = (p) => { - let { some } = useProps(p) + let { some } = useProps(p); /** * Compile to: - * + * * let { some } = useProps(p, ({ some: $0 }) => { some = $0 }); */ - return () => ( -
{some}
- ) -} + return () =>
{some}
; +}; ``` ### 副作用 Unis 保留了和 React 基本一致的 `useEffect` 和 `useLayoutEffect` ,但 deps 是一个返回数组的函数。 -```jsx -import { useEffect } from "@unis/core" +```javascript +import { useEffect } from "@unis/core"; const App = () => { - useEffect( () => { // ... return () => { // 清理... - } + }; }, () => [] // deps 是一个返回数组的函数 - ) + ); - return () => ( -
hello
- ) -} + return () =>
hello
; +}; ``` ### 自定义 hook Unis 的自定义 hook ,在有返回值的场景需要搭配 `use` 方法使用,原因则是前面提到的 Callback Reassign 编译策略。自定义 hook 的命名我们约定以小写字母 `u` 开头,目的是用于区分其他函数,同时在 IDE 的提示下更加方便的导入。 -```jsx -import { use, useState } from "@unis/core" +```javascript +import { use, useState } from "@unis/core"; // 创建自定义 hook 高阶函数 const uCount = () => { - let [count, setCount] = useState(0) - const add = () => setCount(count + 1) - return () => [count, add] -} + let [count, setCount] = useState(0); + const add = () => setCount(count + 1); + return () => [count, add]; +}; // 通过 `use` 使用 hook function App() { - let [count, add] = use(uCount()) + let [count, add] = use(uCount()); /** * Compile to: - * + * * let [count, add] = use(uCount(), ([$0, $1]) => { count = $0; add = $1 }); */ - return () => ( -
{count}
- ) + return () =>
{count}
; } ``` @@ -185,8 +171,8 @@ function App() { ### Fragment -```jsx -import { Fragment } from '@unis/core' +```javascript +import { Fragment } from "@unis/core"; function App() { return () => ( @@ -194,45 +180,76 @@ function App() {
- ) + ); } ``` ### Portal -```jsx -import { createPortal } from '@unis/core' +```javascript +import { createPortal } from "@unis/core"; function App() { - return () => createPortal( -
, - document.body - ) + return () => createPortal(
, document.body); } ``` ### Context -```jsx -import { createContext } from '@unis/core' -import { render } from '@unis/dom' +```javascript +import { createContext } from "@unis/core"; +import { render } from "@unis/dom"; -const ThemeContext = createContext('light') +const ThemeContext = createContext("light"); function App() { - let theme = useContext(ThemeContext) - - return () => ( -
{theme}
- ) + let theme = useContext(ThemeContext); + + return () =>
{theme}
; } render( , - document.querySelector('#root') -) + document.querySelector("#root") +); +``` + +## SSR 服务端渲染 + +服务端 + +```javascript +import express from "express"; +import { renderToString } from "@unis/dom/server"; + +const app = express(); + +app.get("/", (req, res) => { + const SSR_CONTENT = renderToString(
hello world
); + + res.send(` + +
...
+ +
${SSR_CONTENT}
+ + + `); +}); +``` + +客户端 + +```javascript +import { render } from "@unis/dom"; + +render( + , + document.querySelector("#root"), + true // true 代表使用 hydrate (水合)进行渲染,复用 server 端的内容。 +); ``` ## Todo 项目 @@ -245,6 +262,7 @@ render( ## API - Core + - h - h2 (for jsx2) - Fragment diff --git a/README.md b/README.md index 93d749a..f508a10 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,30 @@

-# Unis [中文](README-zh_CN.md) +# Unis -Unis is a simpler and easier to use front-end framework than React +Unis is a frontend framework that is simpler and easier to use than React. -## Install +## Installation ```bash -npm i @unis/unis -```` +npm i @unis/core @unis/dom +``` -## Vite development +## Vite Development -```jsx +```shell npm i vite @unis/vite-preset -D -```` +``` vite.config.js -```jsx +```javascript import { defineConfig } from "vite"; import { unisPreset } from "@unis/vite-preset"; export default defineConfig({ - plugins: [unisPreset()] + plugins: [unisPreset()], }); ``` @@ -35,14 +35,14 @@ tsconfig.json { "compilerOptions": { "jsx": "react-jsx", - "jsxImportSource": "@unis/unis" + "jsxImportSource": "@unis/core" } } ``` index.html -```jsx +```javascript ... @@ -50,116 +50,112 @@ index.html -```` +``` index.tsx -```tsx +```javascript function App() { - return () => ( -
- hello -
- ) + return () =>
hello
; } -render(, document.querySelector('#root')) -```` +render(, document.querySelector("#root")); +``` ## Usage -Unis is not a fork of React, but a brand-new framework that retains the experience of using React. The usage of Unis is very simple, and those familiar with React can get started quickly. +Unis is not a replica of React, but a brand new framework that retains the user experience of React. Unis is easy to use, and those who are familiar with React can quickly get started. ### Components -A component in unis is a higher-order function. +In Unis, the component is a higher-order function. -```jsx -import { render } from '@unis/unis' +```javascript +import { render } from "@unis/dom"; const App = () => { - return () => ( // return a function -
- hello world -
- ) -} + return () => ( + // Returns a function +
hello world
+ ); +}; -render(, document.querySelector('#root')) -```` +render(, document.querySelector("#root")); +``` ### Component State -The usage of `useState` in Unis is similar to that of React, but it should be noted that for the `use` series methods in unis, the definition type must be `let`, because unis uses the Callback Reassign compilation strategy, and rollup-plugin-reassign helps us complete it Callback Reassign code. +The usage of `useState` in Unis is similar to React, but it should be noted that for the `use` method series in Unis, the defined type must be `let`. This is because Unis uses the Callback Reassign compilation strategy, and [@callback-reassign/rollup-plugin](https://github.com/anuoua/callback-reassign) helps us complete the Callback Reassign code. + +```javascript +import { useState } from "@unis/core"; -```jsx const App = () => { - let [msg, setMsg] = useState('hello'); + let [msg, setMsg] = useState("hello"); /** * Compile to: * * let [msg, setMsg] = useState('hello', ([$0, $1]) => { msg = $0; setMsg = $1 }); */ - return () => ( -
{msg}
- ) -} -```` + return () =>
{msg}
; +}; +``` ### Props -Unis will not be able to get the latest value when using props directly, so unis provides useProps. +Directly using `props` in Unis will be unable to get the latest value, so Unis provides `useProps`. + +```javascript +import { useProps } from "@unis/core"; -```jsx const App = (p) => { - let { some } = useProps(p) + let { some } = useProps(p); /** * Compile to: * * let { some } = useProps(p, ({ some: $0 }) => { some = $0 }); */ - return () => ( -
{some}
- ) -} -```` + return () =>
{some}
; +}; +``` -### Side effect +### Side Effects -Unis keeps `useEffect` and `useLayoutEffect` basically the same as React, but deps is a function that returns an array. +Unis retains the familiar `useEffect` and `useLayoutEffect` methods from React, but the `deps` parameter is a function that returns an array. -```jsx -const App = () => { +```javascript +import { useEffect } from "@unis/core"; +const App = () => { useEffect( () => { // ... - return() => { - // clean up... - } + return () => { + // Clean up... + }; }, () => [] // deps is a function that returns an array - ) + ); - return () => ( -
hello
- ) -} -```` + return () =>
hello
; +}; +``` + +### Custom Hook -### Custom hook +For Unis' custom hooks that have a return value, the `use` method should be used accordingly, due to the Callback Reassign compilation strategy mentioned earlier. We conventionally name custom hooks with a lowercase `u` at the beginning, to differentiate them from other functions and make them easy to import with IDE hints. -The custom hook of Unis needs to be used with the `use` method in scenarios with return values, because of the Callback Reassign compilation strategy mentioned above. The naming convention of custom hooks starts with a lowercase letter `u`, which is used to distinguish other functions, and at the same time, it is more convenient to import at the prompt of IDE. +```javascript +import { use, useState } from "@unis/core"; -```jsx -// Create custom hook higher-order function +// Create a higher-order function for the custom hook const uCount = () => { let [count, setCount] = useState(0); const add = () => setCount(count + 1); - return () => [count, add] -} + return () => [count, add]; +}; -// use hook via `use` +// Use the hook through `use` function App() { let [count, add] = use(uCount()); /** @@ -167,18 +163,16 @@ function App() { * * let [count, add] = use(uCount(), ([$0, $1]) => { count = $0; add = $1 }); */ - return () => ( -
{count}
- ) + return () =>
{count}
; } -```` +``` ## Features ### Fragment -```jsx -import { Fragment } from '@unis/unis' +```javascript +import { Fragment } from "@unis/core"; function App() { return () => ( @@ -186,60 +180,92 @@ function App() {
- ) + ); } -```` +``` ### Portal -```jsx -import { createPortal } from '@unis/unis' +```javascript +import { createPortal } from "@unis/core"; function App() { - return () => createPortal( -
, - document.body - ) + return () => createPortal(
, document.body); } -```` +``` ### Context -```jsx -import { createContext, render } from '@unis/unis' +```javascript +import { createContext } from "@unis/core"; +import { render } from "@unis/dom"; -const ThemeContext = createContext('light') +const ThemeContext = createContext("light"); function App() { - let theme = useContext(ThemeContext) - - return () => ( -
{theme}
- ) + let theme = useContext(ThemeContext); + + return () =>
{theme}
; } render( , - document.querySelector('#root') -) -```` + document.querySelector("#root") +); +``` + +## Server-Side Rendering + +Server + +```javascript +import express from "express"; +import { renderToString } from "@unis/dom/server"; + +const app = express(); + +app.get("/", (req, res) => { + const SSR_CONTENT = renderToString(
hello world
); + + res.send(` + +
...
+ +
${SSR_CONTENT}
+ + + `); +}); +``` + +Client + +```javascript +import { render } from "@unis/dom"; + +render( + , + document.querySelector("#root"), + true // true means using hydration to render and reuse the server-side rendered content. +); +``` ## Todo Project -Check out the full project +See complete project at - [packages/unis-example](packages/unis-example) Todo example -- [stackbliz](https://stackblitz.com/edit/vitejs-vite-4cfy2b) Trial +- [stackbliz](https://stackblitz.com/edit/vitejs-vite-8hn3pz) Try it out ## API - Core + - h - h2 (for jsx2) - Fragment - - FGMT: it is Fragment alias, will be removed when vite support `jsxImportSource` - createPortal - createContext - render