From 4820ca5d7398474e1f2a87d0b38f5be866563d90 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Thu, 11 Aug 2022 00:12:32 +0800 Subject: [PATCH 1/6] feat: init hook-store plugin --- examples/with-hook-store/ice.config.mts | 8 +++ examples/with-hook-store/package.json | 21 +++++++ examples/with-hook-store/public/favicon.ico | Bin 0 -> 2719 bytes examples/with-hook-store/src/app.tsx | 3 + examples/with-hook-store/src/document.tsx | 23 +++++++ .../with-hook-store/src/models/useUser.ts | 16 +++++ examples/with-hook-store/src/pages/index.tsx | 17 ++++++ examples/with-hook-store/src/store.ts | 4 ++ examples/with-hook-store/tsconfig.json | 32 ++++++++++ packages/plugin-hook-store/CHANGELOG.md | 1 + packages/plugin-hook-store/README.md | 2 + packages/plugin-hook-store/package.json | 56 ++++++++++++++++++ packages/plugin-hook-store/src/_store.tsx | 10 ++++ packages/plugin-hook-store/src/index.ts | 48 +++++++++++++++ packages/plugin-hook-store/src/runtime.tsx | 22 +++++++ packages/plugin-hook-store/tsconfig.json | 13 ++++ pnpm-lock.yaml | 52 ++++++++++++++++ 17 files changed, 328 insertions(+) create mode 100644 examples/with-hook-store/ice.config.mts create mode 100644 examples/with-hook-store/package.json create mode 100644 examples/with-hook-store/public/favicon.ico create mode 100644 examples/with-hook-store/src/app.tsx create mode 100644 examples/with-hook-store/src/document.tsx create mode 100644 examples/with-hook-store/src/models/useUser.ts create mode 100644 examples/with-hook-store/src/pages/index.tsx create mode 100644 examples/with-hook-store/src/store.ts create mode 100644 examples/with-hook-store/tsconfig.json create mode 100644 packages/plugin-hook-store/CHANGELOG.md create mode 100644 packages/plugin-hook-store/README.md create mode 100644 packages/plugin-hook-store/package.json create mode 100644 packages/plugin-hook-store/src/_store.tsx create mode 100644 packages/plugin-hook-store/src/index.ts create mode 100644 packages/plugin-hook-store/src/runtime.tsx create mode 100644 packages/plugin-hook-store/tsconfig.json diff --git a/examples/with-hook-store/ice.config.mts b/examples/with-hook-store/ice.config.mts new file mode 100644 index 000000000..7b616696f --- /dev/null +++ b/examples/with-hook-store/ice.config.mts @@ -0,0 +1,8 @@ +import { defineConfig } from '@ice/app'; +import store from '@ice/plugin-hook-store'; + +export default defineConfig({ + plugins: [ + store(), + ], +}); diff --git a/examples/with-hook-store/package.json b/examples/with-hook-store/package.json new file mode 100644 index 000000000..84f9db79b --- /dev/null +++ b/examples/with-hook-store/package.json @@ -0,0 +1,21 @@ +{ + "name": "with-hook-store", + "private": true, + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "license": "MIT", + "dependencies": { + "@ice/app": "workspace:*", + "@ice/runtime": "workspace:*" + }, + "devDependencies": { + "@ice/plugin-hook-store": "workspace:*", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "browserslist": "^4.19.3", + "regenerator-runtime": "^0.13.9" + } +} \ No newline at end of file diff --git a/examples/with-hook-store/public/favicon.ico b/examples/with-hook-store/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a2605c57e9d85aabd689ff5c565286dee148ab6d GIT binary patch literal 2719 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 literal 0 HcmV?d00001 diff --git a/examples/with-hook-store/src/app.tsx b/examples/with-hook-store/src/app.tsx new file mode 100644 index 000000000..c1664902e --- /dev/null +++ b/examples/with-hook-store/src/app.tsx @@ -0,0 +1,3 @@ +import { defineAppConfig } from 'ice'; + +export default defineAppConfig({}); diff --git a/examples/with-hook-store/src/document.tsx b/examples/with-hook-store/src/document.tsx new file mode 100644 index 000000000..a61df501e --- /dev/null +++ b/examples/with-hook-store/src/document.tsx @@ -0,0 +1,23 @@ +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +function Document() { + return ( + + + + + + + + + <Links /> + </head> + <body> + <Main /> + <Scripts /> + </body> + </html> + ); +} + +export default Document; diff --git a/examples/with-hook-store/src/models/useUser.ts b/examples/with-hook-store/src/models/useUser.ts new file mode 100644 index 000000000..58e471122 --- /dev/null +++ b/examples/with-hook-store/src/models/useUser.ts @@ -0,0 +1,16 @@ +import { useState } from 'react'; + +function useUser() { + const [age, setAge] = useState(0); + const updateAge = (age: number) => setAge(age); + + const name = 'ICE 3'; + + return { + name, + age, + updateAge, + }; +} + +export default useUser; diff --git a/examples/with-hook-store/src/pages/index.tsx b/examples/with-hook-store/src/pages/index.tsx new file mode 100644 index 000000000..57fcd54bb --- /dev/null +++ b/examples/with-hook-store/src/pages/index.tsx @@ -0,0 +1,17 @@ +import { Link } from 'ice'; +import appStore from '@/store'; + +function Home() { + const { name } = appStore.useHooks('useUser'); + return ( + <> + <div id="username"> + name: {name} + </div> + <Link to="/blog">Blog</Link> + </> + ); +} + + +export default Home; diff --git a/examples/with-hook-store/src/store.ts b/examples/with-hook-store/src/store.ts new file mode 100644 index 000000000..83f29e3ee --- /dev/null +++ b/examples/with-hook-store/src/store.ts @@ -0,0 +1,4 @@ +import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import useUser from './models/useUser'; + +export default createStore({ useUser }); diff --git a/examples/with-hook-store/tsconfig.json b/examples/with-hook-store/tsconfig.json new file mode 100644 index 000000000..7f2f2ffce --- /dev/null +++ b/examples/with-hook-store/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compileOnSave": false, + "buildOnSave": false, + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "module": "esnext", + "target": "es6", + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "lib": ["es6", "dom"], + "sourceMap": true, + "allowJs": true, + "rootDir": "./", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice", "ice.config.*"], + "exclude": ["node_modules", "build", "public"] +} \ No newline at end of file diff --git a/packages/plugin-hook-store/CHANGELOG.md b/packages/plugin-hook-store/CHANGELOG.md new file mode 100644 index 000000000..bbff92b08 --- /dev/null +++ b/packages/plugin-hook-store/CHANGELOG.md @@ -0,0 +1 @@ +# 1.0.0 diff --git a/packages/plugin-hook-store/README.md b/packages/plugin-hook-store/README.md new file mode 100644 index 000000000..4e5972b3f --- /dev/null +++ b/packages/plugin-hook-store/README.md @@ -0,0 +1,2 @@ +# @ice/plugin-hook-store + diff --git a/packages/plugin-hook-store/package.json b/packages/plugin-hook-store/package.json new file mode 100644 index 000000000..0271e7fad --- /dev/null +++ b/packages/plugin-hook-store/package.json @@ -0,0 +1,56 @@ +{ + "name": "@ice/plugin-hook-store", + "version": "1.0.0", + "description": "Lightweight React state management library based on @ice/hooks-store.", + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./esm/index.d.ts", + "import": "./esm/index.js", + "default": "./esm/index.js" + }, + "./runtime": { + "types": "./esm/runtime.d.ts", + "import": "./esm/runtime.js", + "default": "./esm/runtime.js" + }, + "./esm/runtime": { + "types": "./esm/runtime.d.ts", + "import": "./esm/runtime.js", + "default": "./esm/runtime.js" + } + }, + "main": "./esm/index.js", + "types": "./esm/index.d.ts", + "files": [ + "esm", + "!esm/**/*.map" + ], + "dependencies": { + "@ice/hooks-store": "^0.1.1", + "fast-glob": "^3.2.11", + "micromatch": "^4.0.5" + }, + "devDependencies": { + "@ice/types": "^1.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/micromatch": "^4.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "regenerator-runtime": "^0.13.9" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "repository": { + "type": "http", + "url": "https://github.com/ice-lab/ice-next/tree/master/packages/plugin-hook-store" + }, + "scripts": { + "watch": "tsc -w", + "build": "tsc" + } +} \ No newline at end of file diff --git a/packages/plugin-hook-store/src/_store.tsx b/packages/plugin-hook-store/src/_store.tsx new file mode 100644 index 000000000..d92bcf573 --- /dev/null +++ b/packages/plugin-hook-store/src/_store.tsx @@ -0,0 +1,10 @@ +/** + * This file which is imported by the runtime.tsx, is to avoid TS error. + */ +import { createStore } from '@ice/hooks-store'; + +const models = {}; + +const store = createStore(models); + +export default store; \ No newline at end of file diff --git a/packages/plugin-hook-store/src/index.ts b/packages/plugin-hook-store/src/index.ts new file mode 100644 index 000000000..6d9969880 --- /dev/null +++ b/packages/plugin-hook-store/src/index.ts @@ -0,0 +1,48 @@ +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import fg from 'fast-glob'; +import type { Config, Plugin } from '@ice/types'; + +interface Options { + disableResetPageState?: boolean; +} + +const storeFilePattern = '**/store.{js,ts}'; +const ignoreStoreFilePatterns = ['**/models/**', storeFilePattern]; + +const plugin: Plugin<Options> = (options = {}) => ({ + name: '@ice/plugin-hook-store', + setup: ({ onGetConfig, modifyUserConfig, context: { rootDir, userConfig } }) => { + // const { disableResetPageState = false } = options; + const srcDir = path.join(rootDir, 'src'); + + modifyUserConfig('routes', { + ...(userConfig.routes || {}), + ignoreFiles: [...(userConfig?.routes?.ignoreFiles || []), ...ignoreStoreFilePatterns], + }); + + onGetConfig(config => { + // Add app store provider. + const appStorePath = getAppStorePath(srcDir); + if (appStorePath) { + config.alias = { + ...config.alias || {}, + $store: appStorePath, + }; + } + // config.transformPlugins = [ + // ...(config.transformPlugins || []), + // exportStoreProviderPlugin({ pageDir, disableResetPageState }), + // ]; + return config; + }); + }, + runtime: path.join(path.dirname(fileURLToPath(import.meta.url)), 'runtime.js'), +}); + +function getAppStorePath(srcPath: string) { + const result = fg.sync(storeFilePattern, { cwd: srcPath, deep: 1 }); + return result.length ? path.join(srcPath, result[0]) : undefined; +} + +export default plugin; diff --git a/packages/plugin-hook-store/src/runtime.tsx b/packages/plugin-hook-store/src/runtime.tsx new file mode 100644 index 000000000..17c42cb77 --- /dev/null +++ b/packages/plugin-hook-store/src/runtime.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { createStore } from '@ice/hooks-store'; +import type { RuntimePlugin, AppProvider } from '@ice/types'; +import appStore from '$store'; + +const runtime: RuntimePlugin = async ({ addProvider }) => { + if (appStore && Object.prototype.hasOwnProperty.call(appStore, 'Provider')) { + // Add app store Provider + const StoreProvider: AppProvider = ({ children }) => { + return ( + // TODO: support initialStates: https://github.com/ice-lab/ice-next/issues/395#issuecomment-1210552931 + <appStore.Provider> + {children} + </appStore.Provider> + ); + }; + addProvider(StoreProvider); + } +}; + +export { createStore }; +export default runtime; diff --git a/packages/plugin-hook-store/tsconfig.json b/packages/plugin-hook-store/tsconfig.json new file mode 100644 index 000000000..c98231291 --- /dev/null +++ b/packages/plugin-hook-store/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": "./", + "rootDir": "src", + "outDir": "esm", + "jsx": "react", + "paths": { + "$store": ["./src/_store"] + } + }, + "include": ["src"] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95f094a11..87f2ad886 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -305,6 +305,25 @@ importers: '@types/react-dom': 18.0.3 regenerator-runtime: 0.13.9 + examples/with-hook-store: + specifiers: + '@ice/app': workspace:* + '@ice/plugin-hook-store': workspace:* + '@ice/runtime': workspace:* + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + browserslist: ^4.19.3 + regenerator-runtime: ^0.13.9 + dependencies: + '@ice/app': link:../../packages/ice + '@ice/runtime': link:../../packages/runtime + devDependencies: + '@ice/plugin-hook-store': link:../../packages/plugin-hook-store + '@types/react': 18.0.17 + '@types/react-dom': 18.0.6 + browserslist: 4.21.3 + regenerator-runtime: 0.13.9 + examples/with-pha: specifiers: '@ice/app': workspace:* @@ -594,6 +613,31 @@ importers: devDependencies: '@ice/types': link:../types + packages/plugin-hook-store: + specifiers: + '@ice/hooks-store': ^0.1.1 + '@ice/types': ^1.0.0 + '@types/micromatch': ^4.0.2 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + fast-glob: ^3.2.11 + micromatch: ^4.0.5 + react: ^18.2.0 + react-dom: ^18.2.0 + regenerator-runtime: ^0.13.9 + dependencies: + '@ice/hooks-store': 0.1.1_react@18.2.0 + fast-glob: 3.2.11 + micromatch: 4.0.5 + devDependencies: + '@ice/types': link:../types + '@types/micromatch': 4.0.2 + '@types/react': 18.0.17 + '@types/react-dom': 18.0.6 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + regenerator-runtime: 0.13.9 + packages/plugin-pha: specifiers: '@ice/types': ^1.0.0 @@ -5310,6 +5354,14 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@ice/hooks-store/0.1.1_react@18.2.0: + resolution: {integrity: sha512-NQwor8UkgLX6b/fQkQl8Ur4msYUtw5WMKGRjbg4udu1VVkQpUjasXGsjQ+S41t0l9lsoBcZT+kaLcAqN33C82Q==} + peerDependencies: + react: ^16.8.0 + dependencies: + react: 18.2.0 + dev: false + /@ice/pkg-plugin-component/1.0.0: resolution: {integrity: sha512-Mff6Em1RwY2NOZgciQyy2NXL65u9ebHV2Jqb5746vUVEh0l7Xpokb+3djV1pKcgED4wU8pSuSQ6jj+hXd9Ht1Q==} dependencies: From b95da8b906c7338fabe7e14287e6b50037357939 Mon Sep 17 00:00:00 2001 From: luhc228 <luhengchang228@126.com> Date: Thu, 11 Aug 2022 00:26:21 +0800 Subject: [PATCH 2/6] feat: page store --- .../src/pages/counter/index.tsx | 14 ++++ .../src/pages/counter/models/useCounter.ts | 15 ++++ .../src/pages/counter/store.ts | 4 + examples/with-hook-store/src/pages/index.tsx | 2 +- .../src/{_store.tsx => _store.ts} | 0 packages/plugin-hook-store/src/constants.ts | 2 + packages/plugin-hook-store/src/index.ts | 77 +++++++++++++++++-- packages/plugin-hook-store/src/runtime.tsx | 18 ++++- 8 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 examples/with-hook-store/src/pages/counter/index.tsx create mode 100644 examples/with-hook-store/src/pages/counter/models/useCounter.ts create mode 100644 examples/with-hook-store/src/pages/counter/store.ts rename packages/plugin-hook-store/src/{_store.tsx => _store.ts} (100%) create mode 100644 packages/plugin-hook-store/src/constants.ts diff --git a/examples/with-hook-store/src/pages/counter/index.tsx b/examples/with-hook-store/src/pages/counter/index.tsx new file mode 100644 index 000000000..c3c000a81 --- /dev/null +++ b/examples/with-hook-store/src/pages/counter/index.tsx @@ -0,0 +1,14 @@ +import store from './store'; + +function Counter() { + const { count, increment, decrement } = store.useHooks('useCounter'); + return ( + <div> + <button type="button" onClick={() => increment()}>+</button> + <span>{count}</span> + <button type="button" onClick={() => decrement()}>-</button> + </div> + ); +} + +export default Counter; diff --git a/examples/with-hook-store/src/pages/counter/models/useCounter.ts b/examples/with-hook-store/src/pages/counter/models/useCounter.ts new file mode 100644 index 000000000..ab10d03a1 --- /dev/null +++ b/examples/with-hook-store/src/pages/counter/models/useCounter.ts @@ -0,0 +1,15 @@ +import { useState } from 'react'; + +function useCounter() { + const [count, setCount] = useState(0); + const increment = () => setCount(count + 1); + const decrement = () => setCount(count - 1); + + return { + count, + increment, + decrement, + }; +} + +export default useCounter; diff --git a/examples/with-hook-store/src/pages/counter/store.ts b/examples/with-hook-store/src/pages/counter/store.ts new file mode 100644 index 000000000..4195e6f77 --- /dev/null +++ b/examples/with-hook-store/src/pages/counter/store.ts @@ -0,0 +1,4 @@ +import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import useCounter from './models/useCounter'; + +export default createStore({ useCounter }); diff --git a/examples/with-hook-store/src/pages/index.tsx b/examples/with-hook-store/src/pages/index.tsx index 57fcd54bb..bbed95574 100644 --- a/examples/with-hook-store/src/pages/index.tsx +++ b/examples/with-hook-store/src/pages/index.tsx @@ -8,7 +8,7 @@ function Home() { <div id="username"> name: {name} </div> - <Link to="/blog">Blog</Link> + <Link to="/counter">Counter</Link> </> ); } diff --git a/packages/plugin-hook-store/src/_store.tsx b/packages/plugin-hook-store/src/_store.ts similarity index 100% rename from packages/plugin-hook-store/src/_store.tsx rename to packages/plugin-hook-store/src/_store.ts diff --git a/packages/plugin-hook-store/src/constants.ts b/packages/plugin-hook-store/src/constants.ts new file mode 100644 index 000000000..4c487edc6 --- /dev/null +++ b/packages/plugin-hook-store/src/constants.ts @@ -0,0 +1,2 @@ +export const PAGE_STORE_MODULE = '__PAGE_STORE__'; +export const PAGE_STORE_PROVIDER = '__PAGE_STORE_PROVIDER__'; diff --git a/packages/plugin-hook-store/src/index.ts b/packages/plugin-hook-store/src/index.ts index 6d9969880..c62c44aa9 100644 --- a/packages/plugin-hook-store/src/index.ts +++ b/packages/plugin-hook-store/src/index.ts @@ -2,19 +2,22 @@ import * as path from 'path'; import { fileURLToPath } from 'url'; import fg from 'fast-glob'; import type { Config, Plugin } from '@ice/types'; +import micromatch from 'micromatch'; +import { PAGE_STORE_MODULE, PAGE_STORE_PROVIDER } from './constants.js'; interface Options { - disableResetPageState?: boolean; + // TODO: + // disableResetPageState?: boolean; } const storeFilePattern = '**/store.{js,ts}'; const ignoreStoreFilePatterns = ['**/models/**', storeFilePattern]; -const plugin: Plugin<Options> = (options = {}) => ({ +const plugin: Plugin<Options> = () => ({ name: '@ice/plugin-hook-store', setup: ({ onGetConfig, modifyUserConfig, context: { rootDir, userConfig } }) => { - // const { disableResetPageState = false } = options; const srcDir = path.join(rootDir, 'src'); + const pageDir = path.join(srcDir, 'pages'); modifyUserConfig('routes', { ...(userConfig.routes || {}), @@ -30,16 +33,76 @@ const plugin: Plugin<Options> = (options = {}) => ({ $store: appStorePath, }; } - // config.transformPlugins = [ - // ...(config.transformPlugins || []), - // exportStoreProviderPlugin({ pageDir, disableResetPageState }), - // ]; + config.transformPlugins = [ + ...(config.transformPlugins || []), + exportStoreProviderPlugin({ pageDir }), + ]; return config; }); }, runtime: path.join(path.dirname(fileURLToPath(import.meta.url)), 'runtime.js'), }); + +function exportStoreProviderPlugin({ pageDir }: { pageDir: string }): Config['transformPlugins'][0] { + return { + name: 'export-store-provider', + enforce: 'post', + transformInclude: (id) => { + return id.startsWith(pageDir) && !micromatch.isMatch(id, ignoreStoreFilePatterns); + }, + transform: async (source, id) => { + const pageStorePath = getPageStorePath(id); + if (pageStorePath) { + if ( + isLayout(id) || // Current id is layout. + !isLayoutExisted(id) // If current id is route and there is no layout in the current dir. + ) { + return exportPageStore(source); + } + } + return source; + }, + }; +} + +function exportPageStore(source: string) { + const importStoreStatement = `import ${PAGE_STORE_MODULE} from './store';\n`; + const exportStoreProviderStatement = ` +const { Provider: ${PAGE_STORE_PROVIDER} } = ${PAGE_STORE_MODULE}; +export { ${PAGE_STORE_PROVIDER} };`; + + return importStoreStatement + source + exportStoreProviderStatement; +} + +/** + * Get the page store path which is at the same directory level. + * @param {string} id Route absolute path. + * @returns {string|undefined} + */ +function getPageStorePath(id: string): string | undefined { + const dir = path.dirname(id); + const result = fg.sync(storeFilePattern, { cwd: dir, deep: 1 }); + return result.length ? path.join(dir, result[0]) : undefined; +} + +function isLayout(id: string): boolean { + const extname = path.extname(id); + const idWithoutExtname = id.substring(0, id.length - extname.length); + return idWithoutExtname.endsWith('layout'); +} + +/** + * Check the current route component if there is layout.tsx at the same directory level. + * @param {string} id Route absolute path. + * @returns {boolean} + */ +function isLayoutExisted(id: string): boolean { + const dir = path.dirname(id); + const result = fg.sync('layout.{js,jsx,tsx}', { cwd: dir, deep: 1 }); + return !!result.length; +} + function getAppStorePath(srcPath: string) { const result = fg.sync(storeFilePattern, { cwd: srcPath, deep: 1 }); return result.length ? path.join(srcPath, result[0]) : undefined; diff --git a/packages/plugin-hook-store/src/runtime.tsx b/packages/plugin-hook-store/src/runtime.tsx index 17c42cb77..be0817c13 100644 --- a/packages/plugin-hook-store/src/runtime.tsx +++ b/packages/plugin-hook-store/src/runtime.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { createStore } from '@ice/hooks-store'; -import type { RuntimePlugin, AppProvider } from '@ice/types'; +import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/types'; +import { PAGE_STORE_PROVIDER } from './constants.js'; import appStore from '$store'; -const runtime: RuntimePlugin = async ({ addProvider }) => { +const runtime: RuntimePlugin = async ({ addProvider, useAppContext, addWrapper }) => { if (appStore && Object.prototype.hasOwnProperty.call(appStore, 'Provider')) { // Add app store Provider const StoreProvider: AppProvider = ({ children }) => { @@ -16,6 +17,19 @@ const runtime: RuntimePlugin = async ({ addProvider }) => { }; addProvider(StoreProvider); } + + // page store + const StoreProviderWrapper: RouteWrapper = ({ children, routeId }) => { + const { routeModules } = useAppContext(); + const routeModule = routeModules[routeId]; + if (routeModule[PAGE_STORE_PROVIDER]) { + const Provider = routeModule[PAGE_STORE_PROVIDER]; + return <Provider>{children}</Provider>; + } + return <>{children}</>; + }; + + addWrapper(StoreProviderWrapper, true); }; export { createStore }; From 6694c43e6a789c14937808726de50f57760afb34 Mon Sep 17 00:00:00 2001 From: luhc228 <luhengchang228@126.com> Date: Thu, 11 Aug 2022 00:26:21 +0800 Subject: [PATCH 3/6] feat: page store --- .../with-hook-store/src/models/useTodo.ts | 12 +++ .../with-hook-store/src/models/useUser.ts | 16 ---- .../with-hook-store/src/pages/about/index.tsx | 13 ++++ .../src/pages/about/layout.tsx | 9 +++ .../src/pages/about/models/useUser.ts | 6 ++ .../with-hook-store/src/pages/about/store.ts | 4 + examples/with-hook-store/src/pages/index.tsx | 19 ++++- .../src/pages/models/useCounter.ts | 15 ++++ examples/with-hook-store/src/pages/store.ts | 4 + examples/with-hook-store/src/store.ts | 4 +- .../src/{_store.tsx => _store.ts} | 0 packages/plugin-hook-store/src/constants.ts | 2 + packages/plugin-hook-store/src/index.ts | 77 +++++++++++++++++-- packages/plugin-hook-store/src/runtime.tsx | 18 ++++- 14 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 examples/with-hook-store/src/models/useTodo.ts delete mode 100644 examples/with-hook-store/src/models/useUser.ts create mode 100644 examples/with-hook-store/src/pages/about/index.tsx create mode 100644 examples/with-hook-store/src/pages/about/layout.tsx create mode 100644 examples/with-hook-store/src/pages/about/models/useUser.ts create mode 100644 examples/with-hook-store/src/pages/about/store.ts create mode 100644 examples/with-hook-store/src/pages/models/useCounter.ts create mode 100644 examples/with-hook-store/src/pages/store.ts rename packages/plugin-hook-store/src/{_store.tsx => _store.ts} (100%) create mode 100644 packages/plugin-hook-store/src/constants.ts diff --git a/examples/with-hook-store/src/models/useTodo.ts b/examples/with-hook-store/src/models/useTodo.ts new file mode 100644 index 000000000..ac76c0d86 --- /dev/null +++ b/examples/with-hook-store/src/models/useTodo.ts @@ -0,0 +1,12 @@ +import { useState } from 'react'; + +function useTodo() { + const [todos, setTodos] = useState([{ name: 'ICE', id: 'ICE' }]); + + return { + todos, + setTodos, + }; +} + +export default useTodo; diff --git a/examples/with-hook-store/src/models/useUser.ts b/examples/with-hook-store/src/models/useUser.ts deleted file mode 100644 index 58e471122..000000000 --- a/examples/with-hook-store/src/models/useUser.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useState } from 'react'; - -function useUser() { - const [age, setAge] = useState(0); - const updateAge = (age: number) => setAge(age); - - const name = 'ICE 3'; - - return { - name, - age, - updateAge, - }; -} - -export default useUser; diff --git a/examples/with-hook-store/src/pages/about/index.tsx b/examples/with-hook-store/src/pages/about/index.tsx new file mode 100644 index 000000000..c7f8e14a7 --- /dev/null +++ b/examples/with-hook-store/src/pages/about/index.tsx @@ -0,0 +1,13 @@ +import store from './store'; + +function About() { + const { name, age } = store.useHooks('useUser'); + return ( + <> + <div>name: {name}</div> + <div>age: {age}</div> + </> + ); +} + +export default About; diff --git a/examples/with-hook-store/src/pages/about/layout.tsx b/examples/with-hook-store/src/pages/about/layout.tsx new file mode 100644 index 000000000..b76c2b5f2 --- /dev/null +++ b/examples/with-hook-store/src/pages/about/layout.tsx @@ -0,0 +1,9 @@ +import { Outlet } from 'ice'; + +export default function layout() { + return ( + <> + <Outlet /> + </> + ); +} diff --git a/examples/with-hook-store/src/pages/about/models/useUser.ts b/examples/with-hook-store/src/pages/about/models/useUser.ts new file mode 100644 index 000000000..18c1cd2c2 --- /dev/null +++ b/examples/with-hook-store/src/pages/about/models/useUser.ts @@ -0,0 +1,6 @@ +export default function useUser() { + return { + name: 'ICE 3', + age: 5, + }; +} diff --git a/examples/with-hook-store/src/pages/about/store.ts b/examples/with-hook-store/src/pages/about/store.ts new file mode 100644 index 000000000..83f29e3ee --- /dev/null +++ b/examples/with-hook-store/src/pages/about/store.ts @@ -0,0 +1,4 @@ +import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import useUser from './models/useUser'; + +export default createStore({ useUser }); diff --git a/examples/with-hook-store/src/pages/index.tsx b/examples/with-hook-store/src/pages/index.tsx index 57fcd54bb..d9bdfdf9a 100644 --- a/examples/with-hook-store/src/pages/index.tsx +++ b/examples/with-hook-store/src/pages/index.tsx @@ -1,14 +1,25 @@ import { Link } from 'ice'; +import pageStore from './store'; import appStore from '@/store'; function Home() { - const { name } = appStore.useHooks('useUser'); + const { todos } = appStore.useHooks('useTodo'); + const { count, increment, decrement } = pageStore.useHooks('useCounter'); + return ( <> - <div id="username"> - name: {name} + <div> + ToDo List + <ul id="todos"> + {todos.map(todo => (<li key={todo.id}>{todo.name}</li>))} + </ul> + </div> + <div> + <button type="button" onClick={() => increment()}>+</button> + <span>{count}</span> + <button type="button" onClick={() => decrement()}>-</button> </div> - <Link to="/blog">Blog</Link> + <Link to="/about">About</Link> </> ); } diff --git a/examples/with-hook-store/src/pages/models/useCounter.ts b/examples/with-hook-store/src/pages/models/useCounter.ts new file mode 100644 index 000000000..ab10d03a1 --- /dev/null +++ b/examples/with-hook-store/src/pages/models/useCounter.ts @@ -0,0 +1,15 @@ +import { useState } from 'react'; + +function useCounter() { + const [count, setCount] = useState(0); + const increment = () => setCount(count + 1); + const decrement = () => setCount(count - 1); + + return { + count, + increment, + decrement, + }; +} + +export default useCounter; diff --git a/examples/with-hook-store/src/pages/store.ts b/examples/with-hook-store/src/pages/store.ts new file mode 100644 index 000000000..4195e6f77 --- /dev/null +++ b/examples/with-hook-store/src/pages/store.ts @@ -0,0 +1,4 @@ +import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import useCounter from './models/useCounter'; + +export default createStore({ useCounter }); diff --git a/examples/with-hook-store/src/store.ts b/examples/with-hook-store/src/store.ts index 83f29e3ee..a7a8528ab 100644 --- a/examples/with-hook-store/src/store.ts +++ b/examples/with-hook-store/src/store.ts @@ -1,4 +1,4 @@ import { createStore } from '@ice/plugin-hook-store/esm/runtime'; -import useUser from './models/useUser'; +import useTodo from './models/useTodo'; -export default createStore({ useUser }); +export default createStore({ useTodo }); diff --git a/packages/plugin-hook-store/src/_store.tsx b/packages/plugin-hook-store/src/_store.ts similarity index 100% rename from packages/plugin-hook-store/src/_store.tsx rename to packages/plugin-hook-store/src/_store.ts diff --git a/packages/plugin-hook-store/src/constants.ts b/packages/plugin-hook-store/src/constants.ts new file mode 100644 index 000000000..4c487edc6 --- /dev/null +++ b/packages/plugin-hook-store/src/constants.ts @@ -0,0 +1,2 @@ +export const PAGE_STORE_MODULE = '__PAGE_STORE__'; +export const PAGE_STORE_PROVIDER = '__PAGE_STORE_PROVIDER__'; diff --git a/packages/plugin-hook-store/src/index.ts b/packages/plugin-hook-store/src/index.ts index 6d9969880..c62c44aa9 100644 --- a/packages/plugin-hook-store/src/index.ts +++ b/packages/plugin-hook-store/src/index.ts @@ -2,19 +2,22 @@ import * as path from 'path'; import { fileURLToPath } from 'url'; import fg from 'fast-glob'; import type { Config, Plugin } from '@ice/types'; +import micromatch from 'micromatch'; +import { PAGE_STORE_MODULE, PAGE_STORE_PROVIDER } from './constants.js'; interface Options { - disableResetPageState?: boolean; + // TODO: + // disableResetPageState?: boolean; } const storeFilePattern = '**/store.{js,ts}'; const ignoreStoreFilePatterns = ['**/models/**', storeFilePattern]; -const plugin: Plugin<Options> = (options = {}) => ({ +const plugin: Plugin<Options> = () => ({ name: '@ice/plugin-hook-store', setup: ({ onGetConfig, modifyUserConfig, context: { rootDir, userConfig } }) => { - // const { disableResetPageState = false } = options; const srcDir = path.join(rootDir, 'src'); + const pageDir = path.join(srcDir, 'pages'); modifyUserConfig('routes', { ...(userConfig.routes || {}), @@ -30,16 +33,76 @@ const plugin: Plugin<Options> = (options = {}) => ({ $store: appStorePath, }; } - // config.transformPlugins = [ - // ...(config.transformPlugins || []), - // exportStoreProviderPlugin({ pageDir, disableResetPageState }), - // ]; + config.transformPlugins = [ + ...(config.transformPlugins || []), + exportStoreProviderPlugin({ pageDir }), + ]; return config; }); }, runtime: path.join(path.dirname(fileURLToPath(import.meta.url)), 'runtime.js'), }); + +function exportStoreProviderPlugin({ pageDir }: { pageDir: string }): Config['transformPlugins'][0] { + return { + name: 'export-store-provider', + enforce: 'post', + transformInclude: (id) => { + return id.startsWith(pageDir) && !micromatch.isMatch(id, ignoreStoreFilePatterns); + }, + transform: async (source, id) => { + const pageStorePath = getPageStorePath(id); + if (pageStorePath) { + if ( + isLayout(id) || // Current id is layout. + !isLayoutExisted(id) // If current id is route and there is no layout in the current dir. + ) { + return exportPageStore(source); + } + } + return source; + }, + }; +} + +function exportPageStore(source: string) { + const importStoreStatement = `import ${PAGE_STORE_MODULE} from './store';\n`; + const exportStoreProviderStatement = ` +const { Provider: ${PAGE_STORE_PROVIDER} } = ${PAGE_STORE_MODULE}; +export { ${PAGE_STORE_PROVIDER} };`; + + return importStoreStatement + source + exportStoreProviderStatement; +} + +/** + * Get the page store path which is at the same directory level. + * @param {string} id Route absolute path. + * @returns {string|undefined} + */ +function getPageStorePath(id: string): string | undefined { + const dir = path.dirname(id); + const result = fg.sync(storeFilePattern, { cwd: dir, deep: 1 }); + return result.length ? path.join(dir, result[0]) : undefined; +} + +function isLayout(id: string): boolean { + const extname = path.extname(id); + const idWithoutExtname = id.substring(0, id.length - extname.length); + return idWithoutExtname.endsWith('layout'); +} + +/** + * Check the current route component if there is layout.tsx at the same directory level. + * @param {string} id Route absolute path. + * @returns {boolean} + */ +function isLayoutExisted(id: string): boolean { + const dir = path.dirname(id); + const result = fg.sync('layout.{js,jsx,tsx}', { cwd: dir, deep: 1 }); + return !!result.length; +} + function getAppStorePath(srcPath: string) { const result = fg.sync(storeFilePattern, { cwd: srcPath, deep: 1 }); return result.length ? path.join(srcPath, result[0]) : undefined; diff --git a/packages/plugin-hook-store/src/runtime.tsx b/packages/plugin-hook-store/src/runtime.tsx index 17c42cb77..be0817c13 100644 --- a/packages/plugin-hook-store/src/runtime.tsx +++ b/packages/plugin-hook-store/src/runtime.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { createStore } from '@ice/hooks-store'; -import type { RuntimePlugin, AppProvider } from '@ice/types'; +import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/types'; +import { PAGE_STORE_PROVIDER } from './constants.js'; import appStore from '$store'; -const runtime: RuntimePlugin = async ({ addProvider }) => { +const runtime: RuntimePlugin = async ({ addProvider, useAppContext, addWrapper }) => { if (appStore && Object.prototype.hasOwnProperty.call(appStore, 'Provider')) { // Add app store Provider const StoreProvider: AppProvider = ({ children }) => { @@ -16,6 +17,19 @@ const runtime: RuntimePlugin = async ({ addProvider }) => { }; addProvider(StoreProvider); } + + // page store + const StoreProviderWrapper: RouteWrapper = ({ children, routeId }) => { + const { routeModules } = useAppContext(); + const routeModule = routeModules[routeId]; + if (routeModule[PAGE_STORE_PROVIDER]) { + const Provider = routeModule[PAGE_STORE_PROVIDER]; + return <Provider>{children}</Provider>; + } + return <>{children}</>; + }; + + addWrapper(StoreProviderWrapper, true); }; export { createStore }; From 5644e33d53e2d2dda4778fa39a8620171f2b35d0 Mon Sep 17 00:00:00 2001 From: luhc228 <luhengchang228@126.com> Date: Thu, 11 Aug 2022 09:51:28 +0800 Subject: [PATCH 4/6] chore: changelog --- packages/plugin-hook-store/CHANGELOG.md | 6 +++++- packages/plugin-hook-store/README.md | 14 ++++++++++++++ packages/plugin-hook-store/package.json | 2 +- packages/plugin-hook-store/src/_store.ts | 2 +- packages/plugin-hook-store/src/index.ts | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/plugin-hook-store/CHANGELOG.md b/packages/plugin-hook-store/CHANGELOG.md index bbff92b08..eb29e3cbe 100644 --- a/packages/plugin-hook-store/CHANGELOG.md +++ b/packages/plugin-hook-store/CHANGELOG.md @@ -1 +1,5 @@ -# 1.0.0 +# CHANGELOG + +## 1.0.0 + +- feat: init plugin diff --git a/packages/plugin-hook-store/README.md b/packages/plugin-hook-store/README.md index 4e5972b3f..98ed480f2 100644 --- a/packages/plugin-hook-store/README.md +++ b/packages/plugin-hook-store/README.md @@ -1,2 +1,16 @@ # @ice/plugin-hook-store +A plugin of lightweight React Hooks state management used in framework `ICE`. + +## Usage + +```ts +import { defineConfig } from '@ice/app'; +import store from '@ice/plugin-hook-store'; + +export default defineConfig({ + plugins: [ + store(), + ], +}); +``` diff --git a/packages/plugin-hook-store/package.json b/packages/plugin-hook-store/package.json index 0271e7fad..525c35df2 100644 --- a/packages/plugin-hook-store/package.json +++ b/packages/plugin-hook-store/package.json @@ -1,7 +1,7 @@ { "name": "@ice/plugin-hook-store", "version": "1.0.0", - "description": "Lightweight React state management library based on @ice/hooks-store.", + "description": "A plugin of lightweight React Hooks state management based on @ice/hooks-store.", "license": "MIT", "type": "module", "exports": { diff --git a/packages/plugin-hook-store/src/_store.ts b/packages/plugin-hook-store/src/_store.ts index d92bcf573..89b2814a1 100644 --- a/packages/plugin-hook-store/src/_store.ts +++ b/packages/plugin-hook-store/src/_store.ts @@ -7,4 +7,4 @@ const models = {}; const store = createStore(models); -export default store; \ No newline at end of file +export default store; diff --git a/packages/plugin-hook-store/src/index.ts b/packages/plugin-hook-store/src/index.ts index c62c44aa9..a9b2340fe 100644 --- a/packages/plugin-hook-store/src/index.ts +++ b/packages/plugin-hook-store/src/index.ts @@ -6,7 +6,7 @@ import micromatch from 'micromatch'; import { PAGE_STORE_MODULE, PAGE_STORE_PROVIDER } from './constants.js'; interface Options { - // TODO: + // TODO: https://github.com/ice-lab/ice-next/issues/395#issuecomment-1210552931 // disableResetPageState?: boolean; } From 9de1f7a736d4388b98e3e72e2b8830194c5daa15 Mon Sep 17 00:00:00 2001 From: luhc228 <luhengchang228@126.com> Date: Thu, 11 Aug 2022 10:05:49 +0800 Subject: [PATCH 5/6] fix: type error --- packages/plugin-hook-store/src/_store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-hook-store/src/_store.ts b/packages/plugin-hook-store/src/_store.ts index 89b2814a1..e9ffe6434 100644 --- a/packages/plugin-hook-store/src/_store.ts +++ b/packages/plugin-hook-store/src/_store.ts @@ -5,6 +5,6 @@ import { createStore } from '@ice/hooks-store'; const models = {}; -const store = createStore(models); +const store: ReturnType<typeof createStore> = createStore(models); export default store; From 94f892e0a1574f98b61cdbbfb8ef350333d52d40 Mon Sep 17 00:00:00 2001 From: luhc228 <luhengchang228@126.com> Date: Mon, 5 Sep 2022 16:13:57 +0800 Subject: [PATCH 6/6] chore: rename and update version --- .../ice.config.mts | 2 +- .../package.json | 2 +- .../public/favicon.ico | Bin .../src/app.tsx | 0 .../src/document.tsx | 0 .../src/models/useTodo.ts | 0 .../src/pages/about/index.tsx | 5 ++++- .../src/pages/about/layout.tsx | 0 .../src/pages/about/models/useUser.ts | 0 .../src/pages/about/store.ts | 2 +- .../src/pages/index.tsx | 4 ++-- .../src/pages/models/useCounter.ts | 0 .../src/pages/store.ts | 2 +- .../src/store.ts | 2 +- .../tsconfig.json | 0 .../CHANGELOG.md | 0 .../README.md | 4 ++-- .../package.json | 12 ++++++------ .../src/_store.ts | 0 packages/plugin-hooks-store/src/api.ts | 1 + .../src/constants.ts | 0 .../src/index.ts | 16 +++++++++------- .../src/runtime.tsx | 0 .../tsconfig.json | 0 pnpm-lock.yaml | 16 ++++++++-------- 25 files changed, 37 insertions(+), 31 deletions(-) rename examples/{with-hook-store => with-hooks-store}/ice.config.mts (70%) rename examples/{with-hook-store => with-hooks-store}/package.json (90%) rename examples/{with-hook-store => with-hooks-store}/public/favicon.ico (100%) rename examples/{with-hook-store => with-hooks-store}/src/app.tsx (100%) rename examples/{with-hook-store => with-hooks-store}/src/document.tsx (100%) rename examples/{with-hook-store => with-hooks-store}/src/models/useTodo.ts (100%) rename examples/{with-hook-store => with-hooks-store}/src/pages/about/index.tsx (59%) rename examples/{with-hook-store => with-hooks-store}/src/pages/about/layout.tsx (100%) rename examples/{with-hook-store => with-hooks-store}/src/pages/about/models/useUser.ts (100%) rename examples/{with-hook-store => with-hooks-store}/src/pages/about/store.ts (55%) rename examples/{with-hook-store => with-hooks-store}/src/pages/index.tsx (81%) rename examples/{with-hook-store => with-hooks-store}/src/pages/models/useCounter.ts (100%) rename examples/{with-hook-store => with-hooks-store}/src/pages/store.ts (57%) rename examples/{with-hook-store => with-hooks-store}/src/store.ts (55%) rename examples/{with-hook-store => with-hooks-store}/tsconfig.json (100%) rename packages/{plugin-hook-store => plugin-hooks-store}/CHANGELOG.md (100%) rename packages/{plugin-hook-store => plugin-hooks-store}/README.md (74%) rename packages/{plugin-hook-store => plugin-hooks-store}/package.json (85%) rename packages/{plugin-hook-store => plugin-hooks-store}/src/_store.ts (100%) create mode 100644 packages/plugin-hooks-store/src/api.ts rename packages/{plugin-hook-store => plugin-hooks-store}/src/constants.ts (100%) rename packages/{plugin-hook-store => plugin-hooks-store}/src/index.ts (90%) rename packages/{plugin-hook-store => plugin-hooks-store}/src/runtime.tsx (100%) rename packages/{plugin-hook-store => plugin-hooks-store}/tsconfig.json (100%) diff --git a/examples/with-hook-store/ice.config.mts b/examples/with-hooks-store/ice.config.mts similarity index 70% rename from examples/with-hook-store/ice.config.mts rename to examples/with-hooks-store/ice.config.mts index 7b616696f..9b4b21c02 100644 --- a/examples/with-hook-store/ice.config.mts +++ b/examples/with-hooks-store/ice.config.mts @@ -1,5 +1,5 @@ import { defineConfig } from '@ice/app'; -import store from '@ice/plugin-hook-store'; +import store from '@ice/plugin-hooks-store'; export default defineConfig({ plugins: [ diff --git a/examples/with-hook-store/package.json b/examples/with-hooks-store/package.json similarity index 90% rename from examples/with-hook-store/package.json rename to examples/with-hooks-store/package.json index 84f9db79b..3b02b53cc 100644 --- a/examples/with-hook-store/package.json +++ b/examples/with-hooks-store/package.json @@ -12,7 +12,7 @@ "@ice/runtime": "workspace:*" }, "devDependencies": { - "@ice/plugin-hook-store": "workspace:*", + "@ice/plugin-hooks-store": "workspace:*", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "browserslist": "^4.19.3", diff --git a/examples/with-hook-store/public/favicon.ico b/examples/with-hooks-store/public/favicon.ico similarity index 100% rename from examples/with-hook-store/public/favicon.ico rename to examples/with-hooks-store/public/favicon.ico diff --git a/examples/with-hook-store/src/app.tsx b/examples/with-hooks-store/src/app.tsx similarity index 100% rename from examples/with-hook-store/src/app.tsx rename to examples/with-hooks-store/src/app.tsx diff --git a/examples/with-hook-store/src/document.tsx b/examples/with-hooks-store/src/document.tsx similarity index 100% rename from examples/with-hook-store/src/document.tsx rename to examples/with-hooks-store/src/document.tsx diff --git a/examples/with-hook-store/src/models/useTodo.ts b/examples/with-hooks-store/src/models/useTodo.ts similarity index 100% rename from examples/with-hook-store/src/models/useTodo.ts rename to examples/with-hooks-store/src/models/useTodo.ts diff --git a/examples/with-hook-store/src/pages/about/index.tsx b/examples/with-hooks-store/src/pages/about/index.tsx similarity index 59% rename from examples/with-hook-store/src/pages/about/index.tsx rename to examples/with-hooks-store/src/pages/about/index.tsx index c7f8e14a7..0ad5226d8 100644 --- a/examples/with-hook-store/src/pages/about/index.tsx +++ b/examples/with-hooks-store/src/pages/about/index.tsx @@ -1,11 +1,14 @@ +import { Link } from 'ice'; import store from './store'; function About() { - const { name, age } = store.useHooks('useUser'); + const { name, age } = store.useHook('useUser'); return ( <> <div>name: {name}</div> <div>age: {age}</div> + + <Link to="/">Home</Link> </> ); } diff --git a/examples/with-hook-store/src/pages/about/layout.tsx b/examples/with-hooks-store/src/pages/about/layout.tsx similarity index 100% rename from examples/with-hook-store/src/pages/about/layout.tsx rename to examples/with-hooks-store/src/pages/about/layout.tsx diff --git a/examples/with-hook-store/src/pages/about/models/useUser.ts b/examples/with-hooks-store/src/pages/about/models/useUser.ts similarity index 100% rename from examples/with-hook-store/src/pages/about/models/useUser.ts rename to examples/with-hooks-store/src/pages/about/models/useUser.ts diff --git a/examples/with-hook-store/src/pages/about/store.ts b/examples/with-hooks-store/src/pages/about/store.ts similarity index 55% rename from examples/with-hook-store/src/pages/about/store.ts rename to examples/with-hooks-store/src/pages/about/store.ts index 83f29e3ee..8092fa82d 100644 --- a/examples/with-hook-store/src/pages/about/store.ts +++ b/examples/with-hooks-store/src/pages/about/store.ts @@ -1,4 +1,4 @@ -import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import { createStore } from 'ice'; import useUser from './models/useUser'; export default createStore({ useUser }); diff --git a/examples/with-hook-store/src/pages/index.tsx b/examples/with-hooks-store/src/pages/index.tsx similarity index 81% rename from examples/with-hook-store/src/pages/index.tsx rename to examples/with-hooks-store/src/pages/index.tsx index d9bdfdf9a..09f44ed53 100644 --- a/examples/with-hook-store/src/pages/index.tsx +++ b/examples/with-hooks-store/src/pages/index.tsx @@ -3,8 +3,8 @@ import pageStore from './store'; import appStore from '@/store'; function Home() { - const { todos } = appStore.useHooks('useTodo'); - const { count, increment, decrement } = pageStore.useHooks('useCounter'); + const { todos } = appStore.useHook('useTodo'); + const { count, increment, decrement } = pageStore.useHook('useCounter'); return ( <> diff --git a/examples/with-hook-store/src/pages/models/useCounter.ts b/examples/with-hooks-store/src/pages/models/useCounter.ts similarity index 100% rename from examples/with-hook-store/src/pages/models/useCounter.ts rename to examples/with-hooks-store/src/pages/models/useCounter.ts diff --git a/examples/with-hook-store/src/pages/store.ts b/examples/with-hooks-store/src/pages/store.ts similarity index 57% rename from examples/with-hook-store/src/pages/store.ts rename to examples/with-hooks-store/src/pages/store.ts index 4195e6f77..8ad7c8e41 100644 --- a/examples/with-hook-store/src/pages/store.ts +++ b/examples/with-hooks-store/src/pages/store.ts @@ -1,4 +1,4 @@ -import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import { createStore } from 'ice'; import useCounter from './models/useCounter'; export default createStore({ useCounter }); diff --git a/examples/with-hook-store/src/store.ts b/examples/with-hooks-store/src/store.ts similarity index 55% rename from examples/with-hook-store/src/store.ts rename to examples/with-hooks-store/src/store.ts index a7a8528ab..a7a7bc3f2 100644 --- a/examples/with-hook-store/src/store.ts +++ b/examples/with-hooks-store/src/store.ts @@ -1,4 +1,4 @@ -import { createStore } from '@ice/plugin-hook-store/esm/runtime'; +import { createStore } from 'ice'; import useTodo from './models/useTodo'; export default createStore({ useTodo }); diff --git a/examples/with-hook-store/tsconfig.json b/examples/with-hooks-store/tsconfig.json similarity index 100% rename from examples/with-hook-store/tsconfig.json rename to examples/with-hooks-store/tsconfig.json diff --git a/packages/plugin-hook-store/CHANGELOG.md b/packages/plugin-hooks-store/CHANGELOG.md similarity index 100% rename from packages/plugin-hook-store/CHANGELOG.md rename to packages/plugin-hooks-store/CHANGELOG.md diff --git a/packages/plugin-hook-store/README.md b/packages/plugin-hooks-store/README.md similarity index 74% rename from packages/plugin-hook-store/README.md rename to packages/plugin-hooks-store/README.md index 98ed480f2..50c1be6f8 100644 --- a/packages/plugin-hook-store/README.md +++ b/packages/plugin-hooks-store/README.md @@ -1,4 +1,4 @@ -# @ice/plugin-hook-store +# @ice/plugin-hooks-store A plugin of lightweight React Hooks state management used in framework `ICE`. @@ -6,7 +6,7 @@ A plugin of lightweight React Hooks state management used in framework `ICE`. ```ts import { defineConfig } from '@ice/app'; -import store from '@ice/plugin-hook-store'; +import store from '@ice/plugin-hooks-store'; export default defineConfig({ plugins: [ diff --git a/packages/plugin-hook-store/package.json b/packages/plugin-hooks-store/package.json similarity index 85% rename from packages/plugin-hook-store/package.json rename to packages/plugin-hooks-store/package.json index 525c35df2..56d538e42 100644 --- a/packages/plugin-hook-store/package.json +++ b/packages/plugin-hooks-store/package.json @@ -1,5 +1,5 @@ { - "name": "@ice/plugin-hook-store", + "name": "@ice/plugin-hooks-store", "version": "1.0.0", "description": "A plugin of lightweight React Hooks state management based on @ice/hooks-store.", "license": "MIT", @@ -15,10 +15,10 @@ "import": "./esm/runtime.js", "default": "./esm/runtime.js" }, - "./esm/runtime": { - "types": "./esm/runtime.d.ts", - "import": "./esm/runtime.js", - "default": "./esm/runtime.js" + "./api": { + "types": "./esm/api.d.ts", + "import": "./esm/api.js", + "default": "./esm/api.js" } }, "main": "./esm/index.js", @@ -28,7 +28,7 @@ "!esm/**/*.map" ], "dependencies": { - "@ice/hooks-store": "^0.1.1", + "@ice/hooks-store": "^1.0.0-alpha.0", "fast-glob": "^3.2.11", "micromatch": "^4.0.5" }, diff --git a/packages/plugin-hook-store/src/_store.ts b/packages/plugin-hooks-store/src/_store.ts similarity index 100% rename from packages/plugin-hook-store/src/_store.ts rename to packages/plugin-hooks-store/src/_store.ts diff --git a/packages/plugin-hooks-store/src/api.ts b/packages/plugin-hooks-store/src/api.ts new file mode 100644 index 000000000..bda11584e --- /dev/null +++ b/packages/plugin-hooks-store/src/api.ts @@ -0,0 +1 @@ +export { createStore } from '@ice/hooks-store'; diff --git a/packages/plugin-hook-store/src/constants.ts b/packages/plugin-hooks-store/src/constants.ts similarity index 100% rename from packages/plugin-hook-store/src/constants.ts rename to packages/plugin-hooks-store/src/constants.ts diff --git a/packages/plugin-hook-store/src/index.ts b/packages/plugin-hooks-store/src/index.ts similarity index 90% rename from packages/plugin-hook-store/src/index.ts rename to packages/plugin-hooks-store/src/index.ts index a9b2340fe..af27b8a83 100644 --- a/packages/plugin-hook-store/src/index.ts +++ b/packages/plugin-hooks-store/src/index.ts @@ -5,17 +5,12 @@ import type { Config, Plugin } from '@ice/types'; import micromatch from 'micromatch'; import { PAGE_STORE_MODULE, PAGE_STORE_PROVIDER } from './constants.js'; -interface Options { - // TODO: https://github.com/ice-lab/ice-next/issues/395#issuecomment-1210552931 - // disableResetPageState?: boolean; -} - const storeFilePattern = '**/store.{js,ts}'; const ignoreStoreFilePatterns = ['**/models/**', storeFilePattern]; -const plugin: Plugin<Options> = () => ({ +const plugin: Plugin = () => ({ name: '@ice/plugin-hook-store', - setup: ({ onGetConfig, modifyUserConfig, context: { rootDir, userConfig } }) => { + setup: ({ onGetConfig, modifyUserConfig, generator, context: { rootDir, userConfig } }) => { const srcDir = path.join(rootDir, 'src'); const pageDir = path.join(srcDir, 'pages'); @@ -39,6 +34,13 @@ const plugin: Plugin<Options> = () => ({ ]; return config; }); + + // Export store api: createStore, createModel from `.ice/index.ts`. + generator.addExport({ + specifier: ['createStore'], + source: '@ice/plugin-hooks-store/api', + type: false, + }); }, runtime: path.join(path.dirname(fileURLToPath(import.meta.url)), 'runtime.js'), }); diff --git a/packages/plugin-hook-store/src/runtime.tsx b/packages/plugin-hooks-store/src/runtime.tsx similarity index 100% rename from packages/plugin-hook-store/src/runtime.tsx rename to packages/plugin-hooks-store/src/runtime.tsx diff --git a/packages/plugin-hook-store/tsconfig.json b/packages/plugin-hooks-store/tsconfig.json similarity index 100% rename from packages/plugin-hook-store/tsconfig.json rename to packages/plugin-hooks-store/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 87f2ad886..3780e0234 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -308,7 +308,7 @@ importers: examples/with-hook-store: specifiers: '@ice/app': workspace:* - '@ice/plugin-hook-store': workspace:* + '@ice/plugin-hooks-store': workspace:* '@ice/runtime': workspace:* '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 @@ -318,7 +318,7 @@ importers: '@ice/app': link:../../packages/ice '@ice/runtime': link:../../packages/runtime devDependencies: - '@ice/plugin-hook-store': link:../../packages/plugin-hook-store + '@ice/plugin-hooks-store': link:../../packages/plugin-hooks-store '@types/react': 18.0.17 '@types/react-dom': 18.0.6 browserslist: 4.21.3 @@ -613,9 +613,9 @@ importers: devDependencies: '@ice/types': link:../types - packages/plugin-hook-store: + packages/plugin-hooks-store: specifiers: - '@ice/hooks-store': ^0.1.1 + '@ice/hooks-store': ^1.0.0-alpha.0 '@ice/types': ^1.0.0 '@types/micromatch': ^4.0.2 '@types/react': ^18.0.0 @@ -626,7 +626,7 @@ importers: react-dom: ^18.2.0 regenerator-runtime: ^0.13.9 dependencies: - '@ice/hooks-store': 0.1.1_react@18.2.0 + '@ice/hooks-store': 1.0.0-alpha.0_react@18.2.0 fast-glob: 3.2.11 micromatch: 4.0.5 devDependencies: @@ -5354,10 +5354,10 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@ice/hooks-store/0.1.1_react@18.2.0: - resolution: {integrity: sha512-NQwor8UkgLX6b/fQkQl8Ur4msYUtw5WMKGRjbg4udu1VVkQpUjasXGsjQ+S41t0l9lsoBcZT+kaLcAqN33C82Q==} + /@ice/hooks-store/1.0.0-alpha.0_react@18.2.0: + resolution: {integrity: sha512-ElEkwhiyZBfb5TdbpmbknSoXWIK3365mmqMx+i4VU5MSXgb9ciAfcT2tRo8poni7TFHtqtZe/cyBQRTnx+IN3A==} peerDependencies: - react: ^16.8.0 + react: ^16.8 || ^17 || ^18 dependencies: react: 18.2.0 dev: false