From 90212aeaacbdb817a9fd4babff472f19d227ab20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=80=8D=E9=81=A5?= <49544090+SunLxy@users.noreply.github.com> Date: Tue, 8 Mar 2022 15:43:35 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=20react-ssr-enhance?= =?UTF-8?q?d=20=E5=8C=85=20&=20=E5=AE=8C=E5=96=84=20ci=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 1 + .gitignore | 2 +- core/package.json | 2 +- core/src/index.ts | 12 +- core/src/plugins/utils/paths.ts | 24 ++++ core/src/plugins/utils/plugins.ts | 46 ++++++- core/src/utils.ts | 16 +-- example/basic-plugins/package.json | 4 +- example/basic-routes-rematch-new/.gitignore | 19 +++ example/basic-routes-rematch-new/README.md | 29 ++++ example/basic-routes-rematch-new/package.json | 44 ++++++ .../public/favicon.ico | Bin 0 -> 6536 bytes .../public/index.html | 15 ++ .../public/robots.txt | 1 + .../basic-routes-rematch-new/src/client.js | 9 ++ example/basic-routes-rematch-new/src/index.js | 19 +++ .../src/models/demo.js | 13 ++ .../src/models/index.js | 13 ++ .../src/models/login.js | 21 +++ .../src/routes/About/index.js | 9 ++ .../src/routes/Home/index.js | 16 +++ .../src/routes/index.js | 23 ++++ .../basic-routes-rematch-new/src/server.js | 26 ++++ .../src/serverIndex.js | 74 ++++++++++ example/basic-routes/.gitignore | 19 +++ example/basic-routes/README.md | 29 ++++ example/basic-routes/package.json | 40 ++++++ example/basic-routes/public/favicon.ico | Bin 0 -> 6536 bytes example/basic-routes/public/index.html | 15 ++ example/basic-routes/public/robots.txt | 1 + example/basic-routes/src/client.js | 10 ++ example/basic-routes/src/index.js | 13 ++ .../basic-routes/src/routes/About/index.js | 7 + example/basic-routes/src/routes/Home/index.js | 6 + example/basic-routes/src/routes/index.js | 23 ++++ example/basic-routes/src/server.js | 26 ++++ example/basic-routes/src/serverIndex.js | 73 ++++++++++ example/basic/package.json | 4 +- example/react-router-rematch-old/.gitignore | 21 +++ example/react-router-rematch-old/.kktrc.js | 7 + example/react-router-rematch-old/README.md | 44 ++++++ .../react-router-rematch-old/mocker/index.js | 32 +++++ example/react-router-rematch-old/package.json | 55 ++++++++ .../public/favicon.ico | Bin 0 -> 6536 bytes .../public/index.html | 15 ++ .../public/robots.txt | 1 + .../react-router-rematch-old/src/client.js | 37 +++++ .../src/components/Container/index.css | 9 ++ .../src/components/Container/index.js | 27 ++++ .../src/components/Container/index.module.css | 32 +++++ .../src/components/Container/react.svg | 6 + example/react-router-rematch-old/src/index.js | 45 ++++++ .../src/models/about.js | 14 ++ .../src/models/global.js | 23 ++++ .../src/models/home.js | 9 ++ .../src/models/index.js | 13 ++ .../src/routes/about/index.css | 4 + .../src/routes/about/index.js | 31 +++++ .../src/routes/home/home.module.css | 8 ++ .../src/routes/home/index.js | 61 +++++++++ .../src/routes/index.css | 9 ++ .../src/routes/index.js | 128 ++++++++++++++++++ .../src/routes/notmatch/index.js | 25 ++++ .../src/routes/notmatch/index.module.less | 44 ++++++ .../src/routes/repos/avatar.png | Bin 0 -> 3741 bytes .../src/routes/repos/detail/index.css | 4 + .../src/routes/repos/detail/index.js | 26 ++++ .../src/routes/repos/home.module.css | 38 ++++++ .../src/routes/repos/index.js | 38 ++++++ .../src/routes/username/index.css | 4 + .../src/routes/username/index.js | 19 +++ .../react-router-rematch-old/src/server.js | 26 ++++ .../src/serverIndex.js | 62 +++++++++ .../src/store/index.js | 43 ++++++ .../src/utils/history.js | 3 + .../src/utils/request.js | 101 ++++++++++++++ lerna.json | 6 +- package.json | 20 ++- packages/create-kkt-app/bin/create-kkt-app | 55 -------- packages/create-kkt-app/index.js | 6 - packages/create-kkt-app/lib/index.js | 23 ---- packages/create-kkt-app/lib/installDeps.js | 50 ------- packages/create-kkt-app/lib/loadExample.js | 62 --------- packages/create-kkt-app/lib/output.js | 86 ------------ packages/create-kkt-app/lib/registries.js | 7 - packages/create-kkt-app/package.json | 37 ----- .../.gitignore | 0 .../README.md | 0 packages/create-kkt-ssr/package.json | 40 ++++++ packages/create-kkt-ssr/src/cli.ts | 11 ++ packages/create-kkt-ssr/src/utils.ts | 59 ++++++++ packages/create-kkt-ssr/test/cli.test.ts | 49 +++++++ packages/create-kkt-ssr/tsconfig.json | 19 +++ packages/react-ssr-enhanced/package.json | 19 +-- 94 files changed, 1955 insertions(+), 362 deletions(-) create mode 100644 core/src/plugins/utils/paths.ts create mode 100644 example/basic-routes-rematch-new/.gitignore create mode 100644 example/basic-routes-rematch-new/README.md create mode 100644 example/basic-routes-rematch-new/package.json create mode 100644 example/basic-routes-rematch-new/public/favicon.ico create mode 100644 example/basic-routes-rematch-new/public/index.html create mode 100644 example/basic-routes-rematch-new/public/robots.txt create mode 100644 example/basic-routes-rematch-new/src/client.js create mode 100644 example/basic-routes-rematch-new/src/index.js create mode 100644 example/basic-routes-rematch-new/src/models/demo.js create mode 100644 example/basic-routes-rematch-new/src/models/index.js create mode 100644 example/basic-routes-rematch-new/src/models/login.js create mode 100644 example/basic-routes-rematch-new/src/routes/About/index.js create mode 100644 example/basic-routes-rematch-new/src/routes/Home/index.js create mode 100644 example/basic-routes-rematch-new/src/routes/index.js create mode 100644 example/basic-routes-rematch-new/src/server.js create mode 100644 example/basic-routes-rematch-new/src/serverIndex.js create mode 100644 example/basic-routes/.gitignore create mode 100644 example/basic-routes/README.md create mode 100644 example/basic-routes/package.json create mode 100644 example/basic-routes/public/favicon.ico create mode 100644 example/basic-routes/public/index.html create mode 100644 example/basic-routes/public/robots.txt create mode 100644 example/basic-routes/src/client.js create mode 100644 example/basic-routes/src/index.js create mode 100644 example/basic-routes/src/routes/About/index.js create mode 100644 example/basic-routes/src/routes/Home/index.js create mode 100644 example/basic-routes/src/routes/index.js create mode 100644 example/basic-routes/src/server.js create mode 100644 example/basic-routes/src/serverIndex.js create mode 100644 example/react-router-rematch-old/.gitignore create mode 100644 example/react-router-rematch-old/.kktrc.js create mode 100644 example/react-router-rematch-old/README.md create mode 100644 example/react-router-rematch-old/mocker/index.js create mode 100644 example/react-router-rematch-old/package.json create mode 100644 example/react-router-rematch-old/public/favicon.ico create mode 100644 example/react-router-rematch-old/public/index.html create mode 100644 example/react-router-rematch-old/public/robots.txt create mode 100644 example/react-router-rematch-old/src/client.js create mode 100644 example/react-router-rematch-old/src/components/Container/index.css create mode 100644 example/react-router-rematch-old/src/components/Container/index.js create mode 100644 example/react-router-rematch-old/src/components/Container/index.module.css create mode 100644 example/react-router-rematch-old/src/components/Container/react.svg create mode 100644 example/react-router-rematch-old/src/index.js create mode 100644 example/react-router-rematch-old/src/models/about.js create mode 100644 example/react-router-rematch-old/src/models/global.js create mode 100644 example/react-router-rematch-old/src/models/home.js create mode 100644 example/react-router-rematch-old/src/models/index.js create mode 100644 example/react-router-rematch-old/src/routes/about/index.css create mode 100644 example/react-router-rematch-old/src/routes/about/index.js create mode 100644 example/react-router-rematch-old/src/routes/home/home.module.css create mode 100644 example/react-router-rematch-old/src/routes/home/index.js create mode 100644 example/react-router-rematch-old/src/routes/index.css create mode 100644 example/react-router-rematch-old/src/routes/index.js create mode 100644 example/react-router-rematch-old/src/routes/notmatch/index.js create mode 100644 example/react-router-rematch-old/src/routes/notmatch/index.module.less create mode 100644 example/react-router-rematch-old/src/routes/repos/avatar.png create mode 100644 example/react-router-rematch-old/src/routes/repos/detail/index.css create mode 100644 example/react-router-rematch-old/src/routes/repos/detail/index.js create mode 100644 example/react-router-rematch-old/src/routes/repos/home.module.css create mode 100644 example/react-router-rematch-old/src/routes/repos/index.js create mode 100644 example/react-router-rematch-old/src/routes/username/index.css create mode 100644 example/react-router-rematch-old/src/routes/username/index.js create mode 100644 example/react-router-rematch-old/src/server.js create mode 100644 example/react-router-rematch-old/src/serverIndex.js create mode 100644 example/react-router-rematch-old/src/store/index.js create mode 100644 example/react-router-rematch-old/src/utils/history.js create mode 100644 example/react-router-rematch-old/src/utils/request.js delete mode 100755 packages/create-kkt-app/bin/create-kkt-app delete mode 100644 packages/create-kkt-app/index.js delete mode 100644 packages/create-kkt-app/lib/index.js delete mode 100644 packages/create-kkt-app/lib/installDeps.js delete mode 100644 packages/create-kkt-app/lib/loadExample.js delete mode 100644 packages/create-kkt-app/lib/output.js delete mode 100644 packages/create-kkt-app/lib/registries.js delete mode 100644 packages/create-kkt-app/package.json rename packages/{create-kkt-app => create-kkt-ssr}/.gitignore (100%) rename packages/{create-kkt-app => create-kkt-ssr}/README.md (100%) create mode 100644 packages/create-kkt-ssr/package.json create mode 100644 packages/create-kkt-ssr/src/cli.ts create mode 100644 packages/create-kkt-ssr/src/utils.ts create mode 100644 packages/create-kkt-ssr/test/cli.test.ts create mode 100644 packages/create-kkt-ssr/tsconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07cf97a..2fdab5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,3 +59,4 @@ jobs: - run: npm install @jsdevtools/npm-publish -g - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./core/package.json + - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./packages/react-ssr-enhanced/package.json diff --git a/.gitignore b/.gitignore index 6fa4e72..ae1223c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ dist .cache .vscode yarn.lock - +package-lock.json *.bak *.tem *.temp diff --git a/core/package.json b/core/package.json index 03c280d..2ddc161 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@kkt/ssr", - "version": "3.0.0", + "version": "3.0.1", "description": "", "license": "MIT", "main": "lib/index.js", diff --git a/core/src/index.ts b/core/src/index.ts index 6773c03..88bd209 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -64,11 +64,13 @@ const data = { nolog: false, out: "", publicFolder: "", - isWeb: false + isWeb: false, + isEnvDevelopment: false, } process.on("exit", (code) => { - if (data.nolog || code === 1) { + // 开发模式下不需要进行复制 + if (data.nolog || code === 1 || data.isEnvDevelopment) { return; } if (!data.isWeb) { @@ -143,7 +145,8 @@ process.on("exit", (code) => { const target = isWeb ? argvs.target : argvs.target ? ['node14', argvs.target] : 'node14'; fs.ensureDirSync(outDir); - const isEnvDevelopment = scriptName === "watch" + const isEnvDevelopment = data.isEnvDevelopment = scriptName === "watch" + overridePaths(undefined, { ...oPaths }); argvs.overridesWebpack = (conf, env, options) => { @@ -153,10 +156,13 @@ process.on("exit", (code) => { // server 端 css 代码可以可以 isomorphic-style-loader 进行打包 或者 直接分离出 // 处理 module rules 和 plugin 里面的 原始 css loader,是使用 isomorphic-style-loader 还是直接分离做判断 conf = filterPluginsServer(conf, fileName, argvs.minify); + // 代码分割问题 + conf.plugins.push(new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })) } else { // 去除 index.html 模板 conf = filterPluginsClient(conf, argvs.minify); } + conf.entry = inputFile; if (argvs.sourceMap) { conf.devtool = typeof argvs.sourceMap === 'boolean' ? 'source-map' : argvs.sourceMap; diff --git a/core/src/plugins/utils/paths.ts b/core/src/plugins/utils/paths.ts new file mode 100644 index 0000000..65bc2d1 --- /dev/null +++ b/core/src/plugins/utils/paths.ts @@ -0,0 +1,24 @@ +import path from "path"; +import fs from "fs"; +import getPublicUrlOrPath from "react-dev-utils/getPublicUrlOrPath"; + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebook/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = (relativePath: string) => path.resolve(appDirectory, relativePath); + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// webpack needs to know it to put the right ` : ""} + +`); + } + }); + +export default server; diff --git a/example/basic-routes/.gitignore b/example/basic-routes/.gitignore new file mode 100644 index 0000000..217567d --- /dev/null +++ b/example/basic-routes/.gitignore @@ -0,0 +1,19 @@ +node_modules +npm-debug.log* +package-lock.json +coverage +dist +.DS_Store +.cache +.vscode +.env.local +.env.development.local +.env.test.local +.env.production.local + +*.bak +*.tem +*.temp +#.swp +*.*~ +~*.* diff --git a/example/basic-routes/README.md b/example/basic-routes/README.md new file mode 100644 index 0000000..300b31b --- /dev/null +++ b/example/basic-routes/README.md @@ -0,0 +1,29 @@ +Basic Example +--- + +The [react](https://github.com/facebook/react) base application. + +## Development + +Runs the project in development mode. + +```bash +npm run start +``` + +Runs Node Server + +```bash +npm run server +``` + +## production + +Builds the app for production to the build folder. + +```bash +npm run build +``` + +The build is minified and the filenames include the hashes. +Your app is ready to be deployed! diff --git a/example/basic-routes/package.json b/example/basic-routes/package.json new file mode 100644 index 0000000..2091e62 --- /dev/null +++ b/example/basic-routes/package.json @@ -0,0 +1,40 @@ +{ + "name": "@examples/basic-routes", + "version": "3.0.1", + "description": "", + "private": true, + "scripts": { + "server": "node dist/server.js", + "nodemon": "nodemon dist/server.js", + "build": "npm run build:server && npm run build:web", + "build:server": "kkt-ssr build", + "build:web": "kkt-ssr build --target web", + "start": "npm run start:server & npm run start:web", + "start:server": "kkt-ssr watch", + "start:web": "kkt-ssr watch --target web" + }, + "keywords": [], + "dependencies": { + "express": "4.16.4", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-router": "^6.2.1", + "react-router-dom": "^6.2.1" + }, + "devDependencies": { + "@kkt/ssr": "3.0.1", + "kkt": "7.1.5" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/example/basic-routes/public/favicon.ico b/example/basic-routes/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b37ca26b7720fe0a5bf35cdcbc8b7713b94c5ae4 GIT binary patch literal 6536 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 + + + + + + + KKT + + + +
+ + + \ No newline at end of file diff --git a/example/basic-routes/public/robots.txt b/example/basic-routes/public/robots.txt new file mode 100644 index 0000000..7d329b1 --- /dev/null +++ b/example/basic-routes/public/robots.txt @@ -0,0 +1 @@ +User-agent: * diff --git a/example/basic-routes/src/client.js b/example/basic-routes/src/client.js new file mode 100644 index 0000000..af11d8d --- /dev/null +++ b/example/basic-routes/src/client.js @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './routes'; +const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate + +renderMethod(, document.getElementById('root')); + +if (module.hot) { + module.hot.accept(); +} diff --git a/example/basic-routes/src/index.js b/example/basic-routes/src/index.js new file mode 100644 index 0000000..4c335ce --- /dev/null +++ b/example/basic-routes/src/index.js @@ -0,0 +1,13 @@ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './routes'; +import { BrowserRouter } from "react-router-dom"; + +const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate + +renderMethod(, document.getElementById('root')); + +if (module.hot) { + module.hot.accept(); +} diff --git a/example/basic-routes/src/routes/About/index.js b/example/basic-routes/src/routes/About/index.js new file mode 100644 index 0000000..bdc4421 --- /dev/null +++ b/example/basic-routes/src/routes/About/index.js @@ -0,0 +1,7 @@ +import React from "react"; + +const About = () => { + + return
About
+} +export default About; \ No newline at end of file diff --git a/example/basic-routes/src/routes/Home/index.js b/example/basic-routes/src/routes/Home/index.js new file mode 100644 index 0000000..0f6b2fe --- /dev/null +++ b/example/basic-routes/src/routes/Home/index.js @@ -0,0 +1,6 @@ +import React from "react"; + +const Home = () => { + return
home
+} +export default Home; \ No newline at end of file diff --git a/example/basic-routes/src/routes/index.js b/example/basic-routes/src/routes/index.js new file mode 100644 index 0000000..0098ef0 --- /dev/null +++ b/example/basic-routes/src/routes/index.js @@ -0,0 +1,23 @@ +import React from "react"; +import { Route, Routes, Outlet, Link } from "react-router-dom"; +import Home from "./Home" +import About from "./About" + +const Nav = () => { + return
+ home + about + +
+} + +export default () => { + return + } > + } /> + } /> + 无页面} /> + + +} + diff --git a/example/basic-routes/src/server.js b/example/basic-routes/src/server.js new file mode 100644 index 0000000..8bd3965 --- /dev/null +++ b/example/basic-routes/src/server.js @@ -0,0 +1,26 @@ +import http from 'http'; +import app from './serverIndex'; + +const logs = console.log; // eslint-disable-line + +const server = http.createServer(app); +let currentApp = app; +const PORT = process.env.PORT || 3000; +const HOST = process.env.HOST || 'localhost'; +server.listen(PORT, (error) => { + if (error) { + logs(error); + } + logs('🚀 started!', `PORT: http://${HOST}:${PORT}`); +}); + +if (module.hot) { + logs('✅ Server-side HMR Enabled!'); + module.hot.accept('./serverIndex', () => { + logs('🔁 HMR Reloading `./serverIndex`...'); + server.removeListener('request', currentApp); + const newApp = require('./serverIndex').default; // eslint-disable-line + server.on('request', newApp); + currentApp = newApp; + }); +} diff --git a/example/basic-routes/src/serverIndex.js b/example/basic-routes/src/serverIndex.js new file mode 100644 index 0000000..848edac --- /dev/null +++ b/example/basic-routes/src/serverIndex.js @@ -0,0 +1,73 @@ +import React from 'react'; +import express from 'express'; +import { renderToString } from 'react-dom/server'; +import { StaticRouter } from "react-router-dom/server"; +import Path from 'path'; +import FS from 'fs'; + +import App from './routes'; + +// require 方式 打包报错 +const assetsMainifest = new Function(`return ${FS.readFileSync(`${OUTPUT_PUBLIC_PATH}/asset-manifest.json`, "utf-8")}`)() + +const assets = {} + +if (assetsMainifest && assetsMainifest["entrypoints"]) { + Object.values(assetsMainifest.entrypoints).forEach((item) => { + if (/.css$/.test(item)) { + assets.css = item + } + if (/.js$/.test(item)) { + assets.js = item + } + }) +} + +const appDirectory = FS.realpathSync(process.cwd()); +const resolveApp = (relativePath) => Path.resolve(appDirectory, relativePath); +const server = express(); +// server.use(express.static(resolveApp("dist"))) + + + +const render = (props = {}) => { + const html = renderToString( + + + + ); + return html; +}; + +server + .disable('x-powered-by') + .use(express.static(resolveApp('dist'))) + .get('/*', (req, res) => { + let urls = req.url + if (urls === "/") { + urls = "/home" + } + const context = {}; + const markup = render({ url: urls }); + if (req.url === "/") { + res.redirect("/home"); + } else { + res.status(200).send(` + + + + + + Welcome to KKT + + ${assets.css ? `` : ''} + + +
${markup}
+ ${assets.js ? `` : ""} + +`); + } + }); + +export default server; diff --git a/example/basic/package.json b/example/basic/package.json index bbd4ea6..590a355 100644 --- a/example/basic/package.json +++ b/example/basic/package.json @@ -1,6 +1,6 @@ { "name": "@examples/basic", - "version": "3.0.0", + "version": "3.0.1", "description": "", "private": true, "scripts": { @@ -19,7 +19,7 @@ "react-dom": "17.0.2" }, "devDependencies": { - "@kkt/ssr": "3.0.0", + "@kkt/ssr": "3.0.1", "kkt": "7.1.5" }, "browserslist": { diff --git a/example/react-router-rematch-old/.gitignore b/example/react-router-rematch-old/.gitignore new file mode 100644 index 0000000..6d27e58 --- /dev/null +++ b/example/react-router-rematch-old/.gitignore @@ -0,0 +1,21 @@ +node_modules +npm-debug.log* +package-lock.json +yarn.lock +coverage +dist +.DS_Store +.cache +.vscode +.env.local +.env.development.local +.env.test.local +.env.production.local + +*.log +*.bak +*.tem +*.temp +#.swp +*.*~ +~*.* diff --git a/example/react-router-rematch-old/.kktrc.js b/example/react-router-rematch-old/.kktrc.js new file mode 100644 index 0000000..cde8bb4 --- /dev/null +++ b/example/react-router-rematch-old/.kktrc.js @@ -0,0 +1,7 @@ +import { restWebpackManifestPlugin } from '@kkt/ssr/lib/plugins'; +export default (conf, evn, options) => { + if (!options.bundle) { + conf = restWebpackManifestPlugin(conf); + } + return conf; +}; diff --git a/example/react-router-rematch-old/README.md b/example/react-router-rematch-old/README.md new file mode 100644 index 0000000..ab1f037 --- /dev/null +++ b/example/react-router-rematch-old/README.md @@ -0,0 +1,44 @@ +react-router+rematch +--- + +A simple for server side rendering for your React application. This is a basic, bare-bones example of how to use [`@kkt/react-ssr-enhanced`](https://github.com/kktjs/kkt-ssr/tree/master/packages) and [`@kkt/ssr`](https://github.com/kktjs/kkt-ssr). + +[Rematch](https://github.com/rematch/rematch) is [Redux](https://github.com/reduxjs/redux) best practices without the boilerplate. No more action types, action creators, switch statements or thunks. + +[`React`](https://github.com/facebook/react) + [`React Router`](https://github.com/ReactTraining/react-router) + [`Rematch`](https://github.com/rematch/rematch) + [`Express`](https://expressjs.com/) + +## Quick Start + +> ⚠️ A perfect example `react-router+rematch` is recommended for production environments. + +```bash +npx create-kkt-app my-app -e react-router+rematch +cd my-app +npm start +``` + +**development** + +Runs the project in development mode. + +```bash +npm install +npm run start +``` + +**production** + +Builds the app for production to the build folder. + +```bash +npm run build +``` + +The build is minified and the filenames include the hashes. +Your app is ready to be deployed! + +Runs the compiled app in production. + +```bash +npm run server +``` diff --git a/example/react-router-rematch-old/mocker/index.js b/example/react-router-rematch-old/mocker/index.js new file mode 100644 index 0000000..cd3576b --- /dev/null +++ b/example/react-router-rematch-old/mocker/index.js @@ -0,0 +1,32 @@ +// const delay = require('mocker-api/utils/delay'); + +// Whether to disable the proxy +const noProxy = process.env.NO_PROXY === 'true'; + +const proxy = { + // Priority processing. + _proxy: { + proxy: { + '/repos/*': 'https://api.github.com/', + }, + changeHost: true, + }, + 'GET /api/user/:id': (req, res) => { + return res.json({ + id: req.params.id, + username: 'kenny', + sex: 'male', + }); + }, + 'GET /api/user/verify': (req, res) => { + return res.json({ + token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + id: 13, + username: 'kenny', + sex: 'male', + }); + }, +}; + +module.exports = (noProxy ? {} : proxy); +// module.exports = (noProxy ? {} : delay(proxy, 1000)); diff --git a/example/react-router-rematch-old/package.json b/example/react-router-rematch-old/package.json new file mode 100644 index 0000000..03f4215 --- /dev/null +++ b/example/react-router-rematch-old/package.json @@ -0,0 +1,55 @@ +{ + "name": "@examples/basic-routes-rematch-old", + "version": "3.0.1", + "description": "", + "private": true, + "scripts": { + "nodemon": "NODE_ENV=production nodemon dist/server.js", + "build": "npm run build:node && npm run build:web", + "build:ex": "kkt-ssr build --ne false", + "build:web": "kkt-ssr build --target web", + "build:node": "kkt-ssr build", + "start": "npm run start:server & npm run start:web", + "start:server": "kkt-ssr watch", + "start:web": "kkt-ssr watch --target web", + "test": "kkt-ssr test --env=jsdom", + "server": "NODE_ENV=production nodemon dist/server.js" + }, + "keywords": [], + "author": "Kenny Wong ", + "license": "MIT", + "dependencies": { + "@kkt/react-ssr-enhanced": "3.0.1", + "@rematch/core": "1.0.6", + "axios": "0.18.0", + "cookie-parser": "1.4.3", + "cookiejs": "1.0.15", + "express": "4.16.4", + "history": "4.9.0", + "http-proxy-middleware": "0.19.1", + "react": "17.0.2", + "react-content-loader": "4.2.2", + "react-dom": "17.0.2", + "react-dynamic-loadable": "2.0.1", + "react-helmet": "5.2.1", + "react-redux": "7.2.6", + "react-router-dom": "4.3.1" + }, + "devDependencies": { + "@kkt/ssr": "3.0.1", + "kkt": "7.1.5", + "mocker-api": "1.6.6" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/example/react-router-rematch-old/public/favicon.ico b/example/react-router-rematch-old/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b37ca26b7720fe0a5bf35cdcbc8b7713b94c5ae4 GIT binary patch literal 6536 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 + + + + + + + KKT + + + +
+ + + \ No newline at end of file diff --git a/example/react-router-rematch-old/public/robots.txt b/example/react-router-rematch-old/public/robots.txt new file mode 100644 index 0000000..7d329b1 --- /dev/null +++ b/example/react-router-rematch-old/public/robots.txt @@ -0,0 +1 @@ +User-agent: * diff --git a/example/react-router-rematch-old/src/client.js b/example/react-router-rematch-old/src/client.js new file mode 100644 index 0000000..a898133 --- /dev/null +++ b/example/react-router-rematch-old/src/client.js @@ -0,0 +1,37 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { ensureReady, RoutersController } from '@kkt/react-ssr-enhanced'; +import history from './utils/history'; +import { getRouterData } from './routes'; +import { createStore } from './store'; + +const routes = getRouterData(); + +(async () => { + // Initialize store + const store = await createStore(window._KKT_STORE); + ensureReady(routes).then(async (data) => { + // Fix: Expected server HTML to contain a matching in + // Warning: render(): Calling ReactDOM.render() to hydrate server-rendered markup will stop working in React v17. + // Replace the ReactDOM.render() call with ReactDOM.hydrate() if you want React to attach to the server HTML. + // const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate; // eslint-disable-line + const renderMethod = ReactDOM.hydrate; // eslint-disable-line + // The server renders an error and is mounted on the Window object. + // The object exists only on the client side. + window._history = history; + renderMethod( + + + + + , + document.getElementById('root') + ); + }); +})(); + +if (module.hot) { + module.hot.accept(); +} diff --git a/example/react-router-rematch-old/src/components/Container/index.css b/example/react-router-rematch-old/src/components/Container/index.css new file mode 100644 index 0000000..5263848 --- /dev/null +++ b/example/react-router-rematch-old/src/components/Container/index.css @@ -0,0 +1,9 @@ + +.red { + color: red; +} + +.title { + margin: 0; + padding: 10px 0; +} diff --git a/example/react-router-rematch-old/src/components/Container/index.js b/example/react-router-rematch-old/src/components/Container/index.js new file mode 100644 index 0000000..a40a545 --- /dev/null +++ b/example/react-router-rematch-old/src/components/Container/index.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import logo from './react.svg'; +import styles from './index.module.css'; +import './index.css'; + +export default class Container extends React.Component { + render() { + const { title } = this.props; + return ( +
+
+ logo +

{title}

+
+ Home + About + Repos + Repos Detail + No Match +
+
+ {this.props.children} +
+ ); + } +} diff --git a/example/react-router-rematch-old/src/components/Container/index.module.css b/example/react-router-rematch-old/src/components/Container/index.module.css new file mode 100644 index 0000000..bc22e7a --- /dev/null +++ b/example/react-router-rematch-old/src/components/Container/index.module.css @@ -0,0 +1,32 @@ +.home { + text-align: center; +} + +.logo { + animation: logo-spin infinite 20s linear; + height: 80px; + width: 80px; +} + +.header { + background-color: #222; + padding: 20px; + color: white; +} + +.menus a { + color: #fff; +} + +.menus a + a{ + margin-left: 10px; +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/example/react-router-rematch-old/src/components/Container/react.svg b/example/react-router-rematch-old/src/components/Container/react.svg new file mode 100644 index 0000000..2fddb28 --- /dev/null +++ b/example/react-router-rematch-old/src/components/Container/react.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/example/react-router-rematch-old/src/index.js b/example/react-router-rematch-old/src/index.js new file mode 100644 index 0000000..810c3a3 --- /dev/null +++ b/example/react-router-rematch-old/src/index.js @@ -0,0 +1,45 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { ensureReady, RoutersController } from '@kkt/react-ssr-enhanced'; +import history from './utils/history'; +import { getRouterData } from './routes'; +import { createStore } from './store'; + +const routes = getRouterData(); +(async () => { + // Initialize store + const store = await createStore(window._KKT_STORE); + console.log("store", store) + ensureReady(routes).then(async (data) => { + // Fix: Expected server HTML to contain a matching
in + // Warning: render(): Calling ReactDOM.render() to hydrate server-rendered markup will stop working in React v17. + // Replace the ReactDOM.render() call with ReactDOM.hydrate() if you want React to attach to the server HTML. + // const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate; // eslint-disable-line + const renderMethod = ReactDOM.hydrate; // eslint-disable-line + // The server renders an error and is mounted on the Window object. + // The object exists only on the client side. + window._history = history; + renderMethod( + + + + + , + document.getElementById('root') + ); + }); +})(); +// renderMethod( +// +// +// +// +// , +// document.getElementById('root') +// ) + +if (module.hot) { + module.hot.accept(); +} diff --git a/example/react-router-rematch-old/src/models/about.js b/example/react-router-rematch-old/src/models/about.js new file mode 100644 index 0000000..3915990 --- /dev/null +++ b/example/react-router-rematch-old/src/models/about.js @@ -0,0 +1,14 @@ +export default { + state: { + test: 'abouts state test', + }, + reducers: { + updateState: (state, payload) => ({ ...state, ...payload }), + }, + effects: { + async verify() { + // console.log(rootState); // eslint-disable-line + // this.updateState({ test: 'test111' }); + }, + }, +}; diff --git a/example/react-router-rematch-old/src/models/global.js b/example/react-router-rematch-old/src/models/global.js new file mode 100644 index 0000000..7b5c580 --- /dev/null +++ b/example/react-router-rematch-old/src/models/global.js @@ -0,0 +1,23 @@ +import request from '../utils/request'; + +export default { + state: { + test: 'global state test', + name: 'kkt ssr', + token: null, + userinfo: null, + }, + reducers: { + // verify: (state, payload) => ({ ...state, ...payload }), + updateState: (state, payload) => ({ ...state, ...payload }), + }, + effects: () => ({ + async verify({ token }, { global }) { + const verify = await request('/api/user/verify', { body: { token } }); + const state = { ...global, test: 'test:global:111----------->' }; + state.token = verify ? token : null; + state.userinfo = verify; + await this.updateState({ ...state }); + }, + }), +}; diff --git a/example/react-router-rematch-old/src/models/home.js b/example/react-router-rematch-old/src/models/home.js new file mode 100644 index 0000000..73f666f --- /dev/null +++ b/example/react-router-rematch-old/src/models/home.js @@ -0,0 +1,9 @@ +export default { + state: { + test: 'home state test', + }, + reducers: { + updateState: (state, payload) => ({ ...state, ...payload }), + }, + effects: {}, +}; diff --git a/example/react-router-rematch-old/src/models/index.js b/example/react-router-rematch-old/src/models/index.js new file mode 100644 index 0000000..98f6837 --- /dev/null +++ b/example/react-router-rematch-old/src/models/index.js @@ -0,0 +1,13 @@ +import { init } from '@rematch/core'; +import home from "./home" +import global from "./global" +import about from "./about" + +export default init({ + models: { + home, + global, + about + }, + +}) \ No newline at end of file diff --git a/example/react-router-rematch-old/src/routes/about/index.css b/example/react-router-rematch-old/src/routes/about/index.css new file mode 100644 index 0000000..087ad12 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/about/index.css @@ -0,0 +1,4 @@ + +.red { + color: red; +} diff --git a/example/react-router-rematch-old/src/routes/about/index.js b/example/react-router-rematch-old/src/routes/about/index.js new file mode 100644 index 0000000..c57e990 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/about/index.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Helmet } from 'react-helmet'; +import Container from '../../components/Container'; +import './index.css'; + +class About extends React.Component { + render() { + return ( + + + AboutSSS + +
+ About
+ {this.props.test} +
+
+ ); + } +} + +const mapState = ({ about }) => ({ + test: about.test, +}); + +const mapDispatch = ({ global }) => ({ + verify: global.verify, +}); + +export default connect(mapState, mapDispatch)(About); diff --git a/example/react-router-rematch-old/src/routes/home/home.module.css b/example/react-router-rematch-old/src/routes/home/home.module.css new file mode 100644 index 0000000..4a46fb4 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/home/home.module.css @@ -0,0 +1,8 @@ +.resources { + list-style: none; +} + +.resources > li { + display: inline-block; + padding: 1rem; +} diff --git a/example/react-router-rematch-old/src/routes/home/index.js b/example/react-router-rematch-old/src/routes/home/index.js new file mode 100644 index 0000000..4e5f1e4 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/home/index.js @@ -0,0 +1,61 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { connect } from 'react-redux'; +import { Helmet } from 'react-helmet'; +import cookie from 'cookiejs'; +import Container from '../../components/Container'; +import styles from './home.module.css'; + +class Home extends React.Component { + // eslint-disable-next-line + static async getInitialProps({ req, res, match, store, history, location }) { + let token = null; + // only on the server side + if (req && store.dispatch.global && store.dispatch.global.verify && req.cookies) { + token = req.cookies.token; + } + if (typeof window !== 'undefined') { + token = cookie.get('token'); + } + await store.dispatch.global.verify({ token }); + return { whatever: 'Home stuff', isServer: true }; + } + render() { + console.log('~11~:', this.props.whatever); + return ( + + + HomeSSS + +
+ {this.props.test}
+ {this.props.testHome}
+ {this.props.whatever ? this.props.whatever : 'loading'} +
+
+ + ); + } +} + +const mapState = ({ global, home }) => ({ + test: global.test, + testHome: home.test, + name: global.name, +}); + +const mapDispatch = ({ global }) => ({ + verify: global.verify, +}); + +export default connect(mapState, mapDispatch)(Home); diff --git a/example/react-router-rematch-old/src/routes/index.css b/example/react-router-rematch-old/src/routes/index.css new file mode 100644 index 0000000..ff29e8c --- /dev/null +++ b/example/react-router-rematch-old/src/routes/index.css @@ -0,0 +1,9 @@ +html { + font-size: 14px; +} +body { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, + Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; +} diff --git a/example/react-router-rematch-old/src/routes/index.js b/example/react-router-rematch-old/src/routes/index.js new file mode 100644 index 0000000..e688e1d --- /dev/null +++ b/example/react-router-rematch-old/src/routes/index.js @@ -0,0 +1,128 @@ +// import React from 'react'; +// import loadable from 'react-dynamic-loadable'; +// import { store } from '../store'; +// import './index.css'; +// import Home from "./home" +// import About from "./about" +// import Repos from "./repos" +// import ReposDate from "./repos/detail" +// import Notmatch from "./notmatch" +// // wrapper of dynamic +// const dynamicWrapper = (models, component) => loadable({ +// component, +// // LoadingComponent: () =>
...LOADING...
, +// models: () => models.map((m) => { +// return import(`../models/${m}.js`).then((md) => { +// const model = md.default || md; +// const stored = store(); +// if (stored && stored.model) { +// stored.model({ name: m, ...model }); +// } +// }); +// }), +// }); + + +// export const getRouterData = () => { +// let conf = { +// '/': { +// name: 'page-home', +// component: Home, +// // component: dynamicWrapper(['home'], () => import(/* webpackChunkName: 'page-home' */ './home')), +// exact: true, +// }, +// '/about': { +// name: 'page-about', +// component: About, +// // component: dynamicWrapper(['about'], () => import(/* webpackChunkName: 'page-about' */ './about')), +// exact: true, +// }, +// '/repos': { +// name: 'page-repos', +// component: Repos, +// // component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-repos' */ './repos')), +// exact: true, +// }, +// '/repos/detail/:id': { +// name: 'page-detail', +// component: ReposDate, +// // component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-detail' */ './repos/detail')), +// exact: true, +// }, +// '*': { +// name: 'page-not-match', +// component: Notmatch, +// // component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-not-match' */ './notmatch')), +// exact: true, +// }, +// // '/:username': { +// // file: './username', +// // component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-username' */ './username')), +// // exact: true, +// // }, +// }; +// conf = Object.keys(conf).map((path) => { +// return { ...conf[path], path }; +// }); +// return conf; +// }; + +// import React from 'react'; +import loadable from 'react-dynamic-loadable'; +import { store } from '../store'; +import './index.css'; + +// wrapper of dynamic +const dynamicWrapper = (models, component) => loadable({ + component, + // LoadingComponent: () =>
...LOADING...
, + models: () => models.map((m) => { + return import(`../models/${m}.js`).then((md) => { + const model = md.default || md; + const stored = store(); + if (stored && stored.model) { + stored.model({ name: m, ...model }); + } + }); + }), +}); + + +export const getRouterData = () => { + let conf = { + '/': { + name: 'page-home', + component: dynamicWrapper(['home'], () => import(/* webpackChunkName: 'page-home' */ './home')), + exact: true, + }, + '/about': { + name: 'page-about', + component: dynamicWrapper(['about'], () => import(/* webpackChunkName: 'page-about' */ './about')), + exact: true, + }, + '/repos': { + name: 'page-repos', + component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-repos' */ './repos')), + exact: true, + }, + '/repos/detail/:id': { + name: 'page-detail', + component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-detail' */ './repos/detail')), + exact: true, + }, + '*': { + name: 'page-not-match', + component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-not-match' */ './notmatch')), + exact: true, + }, + // '/:username': { + // file: './username', + // component: dynamicWrapper([], () => import(/* webpackChunkName: 'page-username' */ './username')), + // exact: true, + // }, + }; + conf = Object.keys(conf).map((path) => { + return { ...conf[path], path }; + }); + return conf; +}; diff --git a/example/react-router-rematch-old/src/routes/notmatch/index.js b/example/react-router-rematch-old/src/routes/notmatch/index.js new file mode 100644 index 0000000..9b9255a --- /dev/null +++ b/example/react-router-rematch-old/src/routes/notmatch/index.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Helmet from 'react-helmet'; +// import styles from './index.module.less'; +const styles = {} + +export default function NotMatch() { + return ( +
+ + Page not found + +

404

+
+ Page not found +
+
+ This is not the web page you are looking for +
+
+ Back Home +
+
+ ); +} diff --git a/example/react-router-rematch-old/src/routes/notmatch/index.module.less b/example/react-router-rematch-old/src/routes/notmatch/index.module.less new file mode 100644 index 0000000..41bd370 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/notmatch/index.module.less @@ -0,0 +1,44 @@ +.wrapper { + margin: 50px auto 40px auto; + width: 600px; + text-align: center; + color: rgba(0, 0, 0, 0.5); + h1 { + width: 800px; + position: relative; + left: -100px; + letter-spacing: -1px; + line-height: 60px; + font-size: 60px; + font-weight: 100; + margin: 0px 0 50px 0; + text-shadow: 0 1px 0 #fff; + } +} + +.title { + color: rgba(0, 0, 0, 0.5); + margin: 20px 0; + line-height: 1.6; + font-weight: bold; + font-size: 18px; +} + +.btn { + padding: 20px 0; + a { + min-width: 80px; + background-color: #3c6eb9; + text-align: center; + color: #fff; + cursor: pointer; + font-size: 16px; + padding: 6px 10px; + border: none; + border-radius: 2px; + text-decoration: none; + &:hover { + background-color: #154ea2; + } + } +} diff --git a/example/react-router-rematch-old/src/routes/repos/avatar.png b/example/react-router-rematch-old/src/routes/repos/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..4a7cbd93e5b1b1510b5695a598acc6a0a8502bc7 GIT binary patch literal 3741 zcmcgv_d6R<7Z!q`HYG+II%11mqr{4uwMP{RMX4=ztx&5*2Ng3$QL{D`Gqv}gl@={U z)o3Y|)aU#Di0|I#ocD)&&U>Eo-21%exrxR`I*jx@^b`~njJo%pRox)2Gm8@Y9*;BV9#Zd z-N9qd$;`ER4k@2x?r!84ySA0#+n&6&v|2c<*y)J0>IglqfI7`r*(l#G$L%Y=*bZY7 zq5Cf|Lr&KFo=eiu(kkOr zLZ+8yX8emQD|aOho$NO);uegQzHM!7iP^O^mbAA&by8PXXD5i>vxuVj3hp`~5{VO% z4_haR3kwP_L=0Op{#;?%+1U}^4eZ2DCC)~T1Q4+bSWt*seTAQKj~=H8;cvR$0~0v!4<@BW{TO= zx0aNAi#ZgAtR{IQyu7>&ot?iiAqsbc_KACX`emLKS`Q$QC>usb#x9LD(WXR+b? z;^KBOUVdl9j<6th@vqHKwm-GeT1F55~S8V*SiH~R+6^9h!sge zXJ#^i+I_!myS!TZTPr%7CBA`<*p7-?MYhctJhxKQbFyhy@zTEx5}Wb+)ZaUJQZU-q z*U7rn_-;a)Qb5$*`{AqZ{CKqO{4@YygU=uOg6zG8HE0EIf2!7RHK~&(d{r-{T{B?Y zSCE#KMZe)E$S_}1xs%4+!!=WO|Gnechm`PWPLA;e9mo#4%q}Kw)hyj5)@%j#ZO&RJb@;c>^nQdp7Z(w36qt z>^6z*EhXWNxUK5=$Vg7@b}t_>{MY7~av=R`!U_5O&wZW#;(IRh3k#946TPK_vI=VY z)IfC1y1}*b7 zlCck$=jWFZ$YO3{SLB5R`We?{mCFA3qn7MOa7j^(SEGton=+yM5txD{9}o-oB@)C0 zC=Lr&UzgWIgq^6LI3-W(3sXXXiy4NSdQM<~EDojoOP5R|IL zxm#-Ly9yD&6amZ6b$t2HTwe4zJ3EK$ZMKDOvuNYPTr3+w-fH&hngt{bnu1s(28+pK0cm~&376|4Uc65 ze|S4v-+Cl5Hw(EFOgcS`tS_Ib*>IuxOAtiFec`LtZ;%_T!^(2viEZ3;p^9KKaeJl=ip|^edd~T~ z1W4JRJ@ql3`67Q!;ayg7ZAa`kUxHBqr-5`)52!IW_^>adJ1y-oY5P(ftr}gIewtFM zJ4vTP2O432HH78=H43LD!+R_+))Ga7G%H0-x~2G8csKOR=TMi4ESWNk3lA&nADAT8 zd&Ozv)6pM?HTP`#FC$w0x5mRu;~981&O-G>KO1FN++7Lq_V6Il7sGv&NoybDb@nPm z?a(DO7$ln!ByvGYG(H8F*XBABL-3+l>?~yMubm6p9L<_&bhX*P)X|O(vJg+$0Wacd z$0OR#*yeBphChwfe{bEm+S|2OAV{{Fe@lz8R!4^ZYxrp>_5dHahrcAltmmX8(}c-l zC~EgF2gG@kYt|*1I_x@%Z#IoS7i-@VK@Qa~10k|BR2P29AgDUL4!9(fX)y7oSy=6u zl!zbXG{1x2H29Y}y3C7glRKG!geR6y_YA7ooq9iMIa`=Hfod5X;|vad+eyA&Zi*^`kgLU)aOnWEh&;sH&3xfcx%RxGl$~KuSZJUT)EZCV`Mt^noD;t)_3?Mc zkXkX`4)w`v{mz}V`pyPhW~J#KC$dRX%6`I{Rr2+-iV?&9R)%Jr&RsMguZ8vBAeGEEA>V)df?&t{^ym z+teUaMr<4}1TAHsQR_Ay?w>n%beFPQ+@$mcyZDpY2cPfL-~83@7K?qoYx&-uAI&$l zeq;a6>)am1LAh$aTj6#Zu{3yb2n=XA}8Fs)n|>8*iTcb zR5FE1v>v_gr9G!ON&FZEkuRP!xoyBa8O)ij&0|;j)6pDB|D-X=UIhIR5SyKyO&6DE zu2dp9a?lkm&}wrXN^qnb@WyB)O0du{4R5hSqmUzMCTpCwpq!gKcUWTC;&e<7VC6$6 z&~*NS4sl?`gi6rQPl|+}1!?T4A6zJSx8WWqI!5^ASygDMow%coJ7>qE?K@0Bv1rLe z0mUVzo2IG4jx9 z_jsWI%OtOewv%95^U@N0hxF=HuRSlIw|MV+g0Zcw?R_f7i(e4?kFRy(*W{keSJ7c{ zfLH;R*l#Z~G()~lH9y*sF{81U%^LC!u-A$1CgBHnnEHwbV5HlT%O-R}MgMZdwr=de zf^5AO66WLsjmQi@j)q1m0P1T!e|u)wEWg$pbeJ)0#EEWvN4B)6(ctCO@@47n13q(N zk=$fzFe0YH8m;?2CBsW6+qy{U%!-f-h;FGF)m!P{C+I2|a`ZP+8SfT5!I4YcljBWs z@6O-qRuz$Gf%C^E8FF11%DnRB@=j%W!2-Sy(?Ju$>ItD!hNX%YT~6?BjO)41`&>u& z`r~?2Uyq3%DM(ZVbu6g2Kt<;`FJaLA?2?v(Ob=pR@2!(Ny|s{VbLDy-5aaCS(Cja4 z$eHlk(yhW>L(Yg&U{npMF+u{bEn2PeQ(+cA9hOxU|H + + Repos Details + +
+ {this.props.whatever} + Repos 2 Details + {match.params.id} +
+ + ); + } +} diff --git a/example/react-router-rematch-old/src/routes/repos/home.module.css b/example/react-router-rematch-old/src/routes/repos/home.module.css new file mode 100644 index 0000000..db56a5b --- /dev/null +++ b/example/react-router-rematch-old/src/routes/repos/home.module.css @@ -0,0 +1,38 @@ +.home { + text-align: center; +} + +.logo { + animation: logo-spin infinite 20s linear; + height: 80px; +} + +.header { + background-color: #222; + height: 150px; + padding: 20px; + color: white; +} + +.intro { + font-size: large; +} + +.resources { + list-style: none; +} + +.resources > li { + display: inline-block; + padding: 1rem; +} + + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/example/react-router-rematch-old/src/routes/repos/index.js b/example/react-router-rematch-old/src/routes/repos/index.js new file mode 100644 index 0000000..a5c3047 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/repos/index.js @@ -0,0 +1,38 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Helmet } from 'react-helmet'; +import styles from './home.module.css'; +import avatar from './avatar.png'; + +import Container from '../../components/Container'; + +export default class Repos extends React.Component { + // eslint-disable-next-line + static async getInitialProps({ req, res, match, history, location, ...ctx }) { + return { whatever: 'Repos stuff' }; + } + render() { + return ( + + + Repos SSS + +
+ + {this.props.whatever} + +
+
+ ); + } +} diff --git a/example/react-router-rematch-old/src/routes/username/index.css b/example/react-router-rematch-old/src/routes/username/index.css new file mode 100644 index 0000000..32ea4cb --- /dev/null +++ b/example/react-router-rematch-old/src/routes/username/index.css @@ -0,0 +1,4 @@ + +.blue { + color: blue; +} \ No newline at end of file diff --git a/example/react-router-rematch-old/src/routes/username/index.js b/example/react-router-rematch-old/src/routes/username/index.js new file mode 100644 index 0000000..91a5d47 --- /dev/null +++ b/example/react-router-rematch-old/src/routes/username/index.js @@ -0,0 +1,19 @@ +import React from 'react'; +import './index.css'; + + +const Container = import('../../components/Container'); + +class User extends React.Component { + render() { + return ( + +
+ This User Home +
+
+ ); + } +} + +export default User; diff --git a/example/react-router-rematch-old/src/server.js b/example/react-router-rematch-old/src/server.js new file mode 100644 index 0000000..ee58400 --- /dev/null +++ b/example/react-router-rematch-old/src/server.js @@ -0,0 +1,26 @@ + +import http from 'http'; +import app from './serverIndex'; + +const logs = console.log; // eslint-disable-line +const server = http.createServer(app); +let currentApp = app; + +const PORT = process.env.PORT || 3000; +server.listen(PORT, (error) => { + if (error) { + logs(error); + } + logs('🚀 started!', `PORT: http://localhost:${PORT}`); +}); + +if (module.hot) { + logs('✅ Server-side HMR Enabled!'); + module.hot.accept('./server', () => { + logs('🔁 HMR Reloading `./server`...'); + server.removeListener('request', currentApp); + const newApp = require('./server').default; // eslint-disable-line + server.on('request', newApp); + currentApp = newApp; + }); +} diff --git a/example/react-router-rematch-old/src/serverIndex.js b/example/react-router-rematch-old/src/serverIndex.js new file mode 100644 index 0000000..30b0d8f --- /dev/null +++ b/example/react-router-rematch-old/src/serverIndex.js @@ -0,0 +1,62 @@ +import express from 'express'; +import cookieParser from 'cookie-parser'; +import proxy from 'http-proxy-middleware'; +import { render } from '@kkt/react-ssr-enhanced'; +import { getRouterData } from './routes'; +import { createStore } from './store'; +import Path from 'path'; +import FS from 'fs'; + +// const assets = require(process.env.KKT_ASSETS_MANIFEST); // eslint-disable-line + +// require 方式 打包报错 +const assetsMainifest = new Function(`return ${FS.readFileSync(`${OUTPUT_PUBLIC_PATH}/asset-manifest.json`, "utf-8")}`)() + +const appDirectory = FS.realpathSync(process.cwd()); +const resolveApp = (relativePath) => Path.resolve(appDirectory, relativePath); + +// const assets = {} + +// if (assetsMainifest && assetsMainifest["entrypoints"]) { +// Object.values(assetsMainifest.entrypoints).forEach((item) => { +// if (/.css$/.test(item)) { +// assets.css = item +// } +// if (/.js$/.test(item)) { +// assets.js = item +// } +// }) +// } + + +const routes = getRouterData(); +const server = express(); + +server.disable('x-powered-by'); +// API request to pass cookies +// `getInitialProps` gets the required value via `req.cookies.token` +server.use(cookieParser()); +server.use(express.static(resolveApp('dist'))); +server.use('/api', proxy({ + target: `http://${process.env.HOST}:3724`, + changeOrigin: true, +})); +server.get('/*', async (req, res) => { + const store = await createStore(); + try { + const html = await render({ + req, + res, + routes, + assets: assetsMainifest, + store, // This Redux + }); + res.send(html); + } catch (error) { + // eslint-disable-next-line + console.log('html---server--error>>>>:', error); + res.json(error); + } +}); + +export default server; diff --git a/example/react-router-rematch-old/src/store/index.js b/example/react-router-rematch-old/src/store/index.js new file mode 100644 index 0000000..238c397 --- /dev/null +++ b/example/react-router-rematch-old/src/store/index.js @@ -0,0 +1,43 @@ +import { init } from '@rematch/core'; +import cookie from 'cookiejs'; +import global from '../models/global'; +import stores from '../models'; +// let storeInit = {}; + +export const store = () => stores; +export const createStore = async (initialState = {}) => { + // const promises = []; + + // Object.keys({ about: "", global: "", home: "" }).forEach((name) => { + // promises.push(import(`../models/${name}.js`).then((md) => { + // const model = md.default || md; + // model.state = initialState[name] || {}; + // model.name = name; + // return model; + // })); + // }); + + // const models = await Promise.all(promises); + // console.log("models", models) + // storeInit = init({ + // models: models, + // // models: models.length > 0 ? models : { + // // global: global.default, + // // }, + // plugins: [ + // { + // middleware: () => next => async (action) => { + // if (typeof window !== 'undefined') { + // const token = cookie.get('token'); + // if (token) { + // await cookie.set('token', token, 1); + // } + // } + // // do something here + // return next(action); + // }, + // }, + // ], + // }); + return stores; +}; diff --git a/example/react-router-rematch-old/src/utils/history.js b/example/react-router-rematch-old/src/utils/history.js new file mode 100644 index 0000000..9937105 --- /dev/null +++ b/example/react-router-rematch-old/src/utils/history.js @@ -0,0 +1,3 @@ +import { createBrowserHistory } from 'history'; + +export default createBrowserHistory(); diff --git a/example/react-router-rematch-old/src/utils/request.js b/example/react-router-rematch-old/src/utils/request.js new file mode 100644 index 0000000..e55765e --- /dev/null +++ b/example/react-router-rematch-old/src/utils/request.js @@ -0,0 +1,101 @@ +import axios from 'axios'; + +let HOST = process.env.HOST; + +// Ensure host consistency. +if (typeof window !== 'undefined' && window.location && window.location.hostname) { + HOST = window.location.hostname; +} + +axios.defaults.baseURL = `http://${HOST}:${process.env.PORT}`; + +// 拼接url参数 +function splitUrl(url, options) { + let urlNew = url; + const paramsArray = []; + Object.keys(options).forEach(key => paramsArray.push(`${key}=${options[key]}`)); + if (Object.keys(options).length === 0) { + return url; + } + if (/\?/.test(urlNew) === false) { + urlNew = `${urlNew}?${paramsArray.join('&')}`; + } else { + urlNew += `&${paramsArray.join('&')}`; + } + return urlNew; +} + + +// Get the current location. +// const location = history.location; +const codeMessage = { + 200: '服务器成功返回请求的数据。', + 201: '新建或修改数据成功。', + 202: '一个请求已经进入后台排队(异步任务)。', + 204: '删除数据成功。', + 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', + 401: '用户没有权限(令牌、用户名、密码错误)。', + 403: '用户得到授权,但是访问是被禁止的。', + 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', + 406: '请求的格式不可得。', + 410: '请求的资源被永久删除,且不会再得到的。', + 422: '当创建一个对象时,发生一个验证错误。', + 500: '服务器发生错误,请检查服务器。', + 502: '网关错误。', + 503: '服务不可用,服务器暂时过载或维护。', + 504: '网关超时。', +}; + +/** + * Requests a URL, returning a promise. + * + * @param {string} url The URL we want to request + * @param {object} [options] The options we want to pass to "fetch" + * @return {object} An object containing either "data" or "err" + */ +export default function request(url, options = {}) { + const method = options.method || 'GET'; + const newOptions = { + url, + method, + data: options.body, + headers: { + 'Content-Type': options.headers && options.headers.ContentType ? options.headers.ContentType : 'application/json; charset=utf-8', + Accept: 'application/json', + }, + }; + + if (/(GET)/.test(method)) { + newOptions.url = splitUrl(url, { ...options.body }); + delete newOptions.body; + } + + return axios.request(newOptions) + .then(response => response.data) + .catch((err) => { + const response = err.response || {}; + if (response && response.status >= 200 && response.status < 300) { + return response; + } + const errortext = codeMessage[response.status] || response.statusText; + // The server renders the error output. + if (typeof window === 'undefined') { + console.log('request--> :', axios.defaults.baseURL); // eslint-disable-line + console.log('request--> :', response.status, errortext); // eslint-disable-line + console.log('request--> :', response.statusText); // eslint-disable-line + } + if (typeof window !== 'undefined') { + if (response && response.data) { + return response.data; + } + } + const error = new Error(errortext); + error.name = response.status; + error.response = response; + if (response.data) { + // response.data + return ''; + } + throw error; + }); +} diff --git a/lerna.json b/lerna.json index 7d97903..712fdf6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,9 @@ { "packages": [ "example/*", - "core/" + "core/", + "packages/create-kkt-ssr", + "packages/react-ssr-enhanced" ], - "version": "3.0.0" + "version": "3.0.1" } \ No newline at end of file diff --git a/package.json b/package.json index e16ee39..a158413 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,13 @@ "version": "1.3.1", "description": "A baseline for server side rendering for your React application.", "scripts": { - "build": "npm run build:ssr", + "build": "npm run build:ssr && npm run build:enhanced", "-----build:ssr-----": "----------", "build:ssr": "lerna exec --scope @kkt/ssr -- npm run build", "watch:ssr": "lerna exec --scope @kkt/ssr -- npm run watch", + "-----build:react-ssr-enhanced-----": "----------", + "build:enhanced": "lerna exec --scope @kkt/react-ssr-enhanced -- npm run build", + "watch:enhanced": "lerna exec --scope @kkt/react-ssr-enhanced -- npm run watch", "-------------": "-------------------", "hoist": "lerna bootstrap --hoist", "bootstrap": "lerna bootstrap", @@ -22,6 +25,7 @@ "remove:yarn": "lerna exec --scope @kkt/* --scope @example/* -- rm -rf yarn.lock", "remove:lib": "lerna exec --scope @kkt/* -- rm -rf ./lib", "remove:esm": "lerna exec --scope @kkt/* -- rm -rf ./esm", + "test": "tsbb test", "tsbb": "tsbb", "lerna": "lerna" }, @@ -42,11 +46,19 @@ "prettier --write" ] }, + "jest": { + "testMatch": [ + "/test/*.test.{js,ts}" + ] + }, "devDependencies": { - "lerna": "4.0.0", - "tsbb": "3.7.0", "husky": "7.0.4", + "lerna": "4.0.0", "lint-staged": "12.3.4", - "prettier": "2.5.1" + "prettier": "2.5.1", + "tsbb": "3.7.0" + }, + "dependencies": { + "hoist": "^0.0.6" } } \ No newline at end of file diff --git a/packages/create-kkt-app/bin/create-kkt-app b/packages/create-kkt-app/bin/create-kkt-app deleted file mode 100755 index d6082ea..0000000 --- a/packages/create-kkt-app/bin/create-kkt-app +++ /dev/null @@ -1,55 +0,0 @@ -#! /usr/bin/env node - -const program = require('commander'); -const color = require('colors-cli/safe'); -const pkg = require('../package.json'); -const lib = require('..'); - -const logs = console.log; // eslint-disable-line -const exampleHelp = 'Example from https://github.com/kktjs/kkt-ssr/tree/master/example example-path'; - -program - .description('A baseline for server side rendering for your React application.') - .version(pkg.version, '-v, --version') - .usage(' [options]'); - - -program - .arguments('') - .usage(`${color.green('')} [options]`) - .option('-e, --example ', exampleHelp, 'basic'); - -program.on('--help', () => { - logs('\nExamples:'); - logs(); - logs(` $ ${color.green('create-kkt-app')} ${color.yellow('')}`); - logs(` $ ${color.green('create-kkt-app')} my-app`); - logs(` $ ${color.green('create-kkt-app -e')} ${color.yellow('react-router')} my-app`); - logs(` $ npx ${color.green('create-kkt-app')} my-app`); - logs(` $ npx ${color.green('create-kkt-app -e')} ${color.yellow('react-router')} my-app`); - logs(` $ yarn ${color.green('kkt-app')} my-app`); - logs(` $ yarn ${color.green('kkt-app -e')} ${color.yellow('react-router')} my-app`); - logs(); - logs(); -}); -// npx create-kkt-app my-app -program.parse(process.argv); - -if (!process.argv.slice(2).length) { - program.outputHelp(); -} - -if (program.args.length > 0) { - lib.createKKTApp({ - projectName: program.args[0], - example: program.example, - }); -} else { - // eslint-disable-next-line - console.log(` - Only ${color.green('')} is required. - If you have any problems, do not hesitate to file an issue:\n - ${color.cyan('https://github.com/kktjs/kkt-ssr/issues/new')} - `); - process.exit(1); -} diff --git a/packages/create-kkt-app/index.js b/packages/create-kkt-app/index.js deleted file mode 100644 index 4f94b49..0000000 --- a/packages/create-kkt-app/index.js +++ /dev/null @@ -1,6 +0,0 @@ - -const createKKT = require('./lib'); - -module.exports = { - createKKTApp: createKKT, -}; diff --git a/packages/create-kkt-app/lib/index.js b/packages/create-kkt-app/lib/index.js deleted file mode 100644 index c7e2a2b..0000000 --- a/packages/create-kkt-app/lib/index.js +++ /dev/null @@ -1,23 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const color = require('colors-cli/safe'); -const loadExample = require('./loadExample'); - -module.exports = function createKKTApp({ example, projectName }) { - const projectPath = path.join(process.cwd(), projectName); - - if (fs.existsSync(projectPath)) { - // eslint-disable-next-line - console.log(` - Uh oh! Looks like there's already a directory called ${color.red(projectName)}. - ${color.yellow('Please try a different name or delete that folder.')} - Path: ${projectPath} - `); - process.exit(1); - } - loadExample({ example, projectName, projectPath }) - // .then() - .catch((err) => { - throw err; - }); -}; diff --git a/packages/create-kkt-app/lib/installDeps.js b/packages/create-kkt-app/lib/installDeps.js deleted file mode 100644 index c80a5a9..0000000 --- a/packages/create-kkt-app/lib/installDeps.js +++ /dev/null @@ -1,50 +0,0 @@ -const execa = require('execa'); -const registries = require('./registries'); - -const taobaoDistURL = 'https://npm.taobao.org/dist'; - -async function addRegistryToArgs(command, args, cliRegistry) { - if (command === 'yarn' && cliRegistry) { - throw new Error( - 'Inline registry is not supported when using yarn. ' + - `Please run \`yarn config set registry ${cliRegistry}\` before running kkt` - ); - } - if (cliRegistry) { - args.push(`--registry=${cliRegistry}`); - if (cliRegistry === registries.taobao) { - args.push(`--disturl=${taobaoDistURL}`); - } - } -} - -function executeCommand(command, args, targetDir) { - return new Promise((resolve, reject) => { - const child = execa(command, args, { - cwd: targetDir, - stdio: ['inherit', 'inherit', command === 'yarn' ? 'pipe' : 'inherit'], - }); - - child.on('close', (code) => { - if (code !== 0) { - reject(new Error(`command failed: ${command} ${args.join(' ')}`)); - return; - } - resolve(); - }); - }); -} - - -exports.installDeps = async function installDeps(targetDir, command, cliRegistry) { - const args = []; - if (command === 'npm') { - args.push('install', '--loglevel', 'error'); - } else { - throw new Error(`Unknown package manager: ${command}`); - } - - await addRegistryToArgs(command, args, cliRegistry); - await executeCommand(command, args, targetDir); -}; - diff --git a/packages/create-kkt-app/lib/loadExample.js b/packages/create-kkt-app/lib/loadExample.js deleted file mode 100644 index e05459d..0000000 --- a/packages/create-kkt-app/lib/loadExample.js +++ /dev/null @@ -1,62 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const exec = require('execa'); -const axios = require('axios'); -const color = require('colors-cli/safe'); -const output = require('./output'); -const { installDeps } = require('./installDeps'); - -module.exports = function loadExample({ example, projectName, projectPath }) { - const cmds = [ - `mkdir -p ${projectName}`, - `curl https://codeload.github.com/kktjs/kkt-ssr/tar.gz/master | tar -xz -C ${projectName} --strip=3 kkt-ssr-master/example/${example}`, - ]; - - const stopExampleSpinner = output.wait( - `Downloading files for ${output.cmd(example)} example` - ); - - const cmdPromises = cmds.map((cmd) => { - return exec.shell(cmd); - }); - - return Promise.all(cmdPromises).then(async () => { - stopExampleSpinner(); - output.success( - `Downloaded ${output.cmd(example)} files for ${output.cmd(projectName)}` - ); - // settings dependencies on the '@kkt/ssr' version. - const dependName = '@kkt/ssr'; - const stopKKTVersionSpinner = await output.wait(`settings dependencies on the ${output.cmd(dependName)} version.`); - const pkg = await axios.get('https://raw.githubusercontent.com/kktjs/kkt-ssr/master/package.json'); - stopKKTVersionSpinner(); - if (pkg && pkg.data) { - const appPkgPath = path.join(projectPath, 'package.json'); - const appPkg = require(`${appPkgPath}`); // eslint-disable-line - if (appPkg) { - if (appPkg.dependencies && appPkg.dependencies[dependName]) { - appPkg.dependencies[dependName] = `^${pkg.data.version}`; - } - if (appPkg.devDependencies && appPkg.devDependencies[dependName]) { - appPkg.devDependencies[dependName] = `^${pkg.data.version}`; - } - fs.writeFileSync(appPkgPath, JSON.stringify(appPkg, null, 2)); - } - output.success( - `Dependent on ${output.cmd(dependName)} version has been set.` - ); - } - await installDeps(projectPath, 'npm'); - // eslint-disable-next-line - console.log(`🎉 ${color.green('✔')} successfully installed ${color.cyan(projectName)} dependencies..`); - // eslint-disable-next-line - console.log( - '👉 Get started with the following commands:\n\n' + - `${projectPath === process.cwd() ? '' : color.cyan(` ${color.white('$')} cd ${projectName}\n`)}` + - ` ${color.cyan(`${color.white('$')} npm run start\n\n`)}` - ); - }).catch((err) => { - stopExampleSpinner(); - throw err; - }); -}; diff --git a/packages/create-kkt-app/lib/output.js b/packages/create-kkt-app/lib/output.js deleted file mode 100644 index f0ad17e..0000000 --- a/packages/create-kkt-app/lib/output.js +++ /dev/null @@ -1,86 +0,0 @@ -const { eraseLine } = require('ansi-escapes'); -const color = require('colors-cli/safe'); -const ora = require('ora'); -const ms = require('ms'); - -exports.info = (msg) => { - // eslint-disable-next-line - console.log(`${color.black('>')} ${msg}`); -}; - -exports.error = (msg) => { - if (msg instanceof Error) { - msg = msg.message; - } - - // eslint-disable-next-line - console.error(`${color.red('> Error!')} ${msg}`); -}; - -exports.success = (msg) => { - // eslint-disable-next-line - console.log(`${color.green('> Success!')} ${msg}`); -}; - -exports.time = () => { - const start = new Date(); - return color.black(`[${ms(new Date() - start)}]`); -}; - -exports.wait = (msg) => { - const spinner = ora(color.green(msg)); - spinner.color = 'blue'; - spinner.start(); - - return () => { - spinner.stop(); - process.stdout.write(eraseLine); - }; -}; - -exports.prompt = (opts) => { - return new Promise((resolve, reject) => { - opts.forEach((val, i) => { - const text = val[1]; - // eslint-disable-next-line - console.log(`${color.black('>')} [${color.bold(i + 1)}] ${text}`); - }); - - const ondata = (v) => { - const s = v.toString(); - - function cleanup() { - process.stdin.setRawMode(false); - process.stdin.removeListener('data', ondata); - } - - if (s === '\u0003') { - cleanup(); - reject(new Error('Aborted')); - return; - } - - const n = Number(s); - if (opts[n - 1]) { - cleanup(); - resolve(opts[n - 1][0]); - } - }; - - process.stdin.setRawMode(true); - process.stdin.resume(); - process.stdin.on('data', ondata); - }); -}; - -exports.cmd = (cmd) => { - return color.bold(color.cyan(cmd)); -}; - -exports.code = (cmd) => { - return `${color.black('`')}${color.bold(cmd)}${color.black('`')}`; -}; - -exports.param = (param) => { - return color.bold(`${color.black('{')}${color.bold(param)}${color.black('}')}`); -}; diff --git a/packages/create-kkt-app/lib/registries.js b/packages/create-kkt-app/lib/registries.js deleted file mode 100644 index aab44b7..0000000 --- a/packages/create-kkt-app/lib/registries.js +++ /dev/null @@ -1,7 +0,0 @@ -const registries = { - npm: 'https://registry.npmjs.org', - yarn: 'https://registry.yarnpkg.com', - taobao: 'https://registry.npm.taobao.org', -}; - -module.exports = registries; diff --git a/packages/create-kkt-app/package.json b/packages/create-kkt-app/package.json deleted file mode 100644 index 5b0e5b0..0000000 --- a/packages/create-kkt-app/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "create-kkt-app", - "version": "1.0.3", - "description": "CLI tool to bootstrap KKT applications with no configuration", - "bin": { - "create-kkt-app": "./bin/create-kkt-app" - }, - "main": "index.js", - "engines": { - "node": ">=8" - }, - "repository": { - "type": "git", - "url": "https://github.com/kktjs/kkt-ssr/tree/master/packages/create-kkt-app" - }, - "keywords": [ - "react", - "react-router", - "redux", - "rematch", - "webpack", - "express", - "ssr", - "next.js" - ], - "author": "Kenny Wong (https://github.com/jaywcjlove)", - "license": "MIT", - "dependencies": { - "ansi-escapes": "5.0.0", - "axios": "0.26.0", - "colors-cli": "1.0.28", - "commander": "9.0.0", - "execa": "6.1.0", - "ms": "2.1.3", - "ora": "6.1.0" - } -} \ No newline at end of file diff --git a/packages/create-kkt-app/.gitignore b/packages/create-kkt-ssr/.gitignore similarity index 100% rename from packages/create-kkt-app/.gitignore rename to packages/create-kkt-ssr/.gitignore diff --git a/packages/create-kkt-app/README.md b/packages/create-kkt-ssr/README.md similarity index 100% rename from packages/create-kkt-app/README.md rename to packages/create-kkt-ssr/README.md diff --git a/packages/create-kkt-ssr/package.json b/packages/create-kkt-ssr/package.json new file mode 100644 index 0000000..5f1b9f0 --- /dev/null +++ b/packages/create-kkt-ssr/package.json @@ -0,0 +1,40 @@ +{ + "name": "create-kkt-ssr", + "version": "3.0.1", + "description": "CLI tool to bootstrap KKT applications with no configuration", + "main": "lib/index.js", + "bin": { + "create-kkt-ssr": "lib/index.js" + }, + "scripts": { + "build": "tsbb build --disable-babel --file-names src/cli.ts", + "watch": "tsbb watch --disable-babel --file-names src/cli.ts", + "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,md,json}'", + "coverage": "tsbb test --coverage --detectOpenHandles", + "test": "tsbb test --detectOpenHandles" + }, + "repository": { + "type": "git", + "url": "https://github.com/kktjs/kkt-ssr/tree/master/packages/create-kkt-ssr" + }, + "keywords": [ + "react", + "react-router", + "redux", + "rematch", + "webpack", + "express", + "ssr", + "next.js" + ], + "author": "Kenny Wong (https://github.com/jaywcjlove)", + "license": "MIT", + "devDependencies": { + "prettier": "~2.5.1", + "pretty-quick": "~3.1.3", + "tsbb": "~3.7.0" + }, + "dependencies": { + "create-kkt": "3.0.0" + } +} diff --git a/packages/create-kkt-ssr/src/cli.ts b/packages/create-kkt-ssr/src/cli.ts new file mode 100644 index 0000000..8d6fc09 --- /dev/null +++ b/packages/create-kkt-ssr/src/cli.ts @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +import { run } from './utils'; + +try { + run(); +} catch (error) { + console.log(`\x1b[31m${error.message}\x1b[0m`); + console.log(error); + process.exit(1); +} diff --git a/packages/create-kkt-ssr/src/utils.ts b/packages/create-kkt-ssr/src/utils.ts new file mode 100644 index 0000000..2344cee --- /dev/null +++ b/packages/create-kkt-ssr/src/utils.ts @@ -0,0 +1,59 @@ +import minimist from 'minimist'; +import { create } from 'create-kkt'; + +export async function run(): Promise { + const argvs = minimist(process.argv.slice(2), { + alias: { + output: 'o', + version: 'v', + force: 'f', + path: 'p', + example: 'e', + }, + default: { + path: 'https://kktjs.github.io/kkt-ssr/zip/', + output: '.', + force: false, + example: 'basic', + }, + }); + if (argvs.h || argvs.help) { + console.log(helpCli); + return; + } + const { version } = require('../package.json'); + if (argvs.v || argvs.version) { + console.log(`\n create-kkt-ssr v${version}\n`); + return; + } + argvs.appName = argvs._[0]; + argvs.example = argvs.e = String(argvs.example).toLocaleLowerCase(); + await create(argvs, helpExample); +} + +export const helpExample: string = `Example: + + \x1b[35myarn\x1b[0m create kkt-ssr \x1b[33mappName\x1b[0m + \x1b[35mnpx\x1b[0m create-kkt-ssr \x1b[33mmy-app\x1b[0m + \x1b[35mnpm\x1b[0m create kkt-ssr \x1b[33mmy-app\x1b[0m + \x1b[35mnpm\x1b[0m create kkt-ssr \x1b[33mmy-app\x1b[0m -f + \x1b[35mnpm\x1b[0m create kkt-ssr \x1b[33mmy-app\x1b[0m -p \x1b[34mhttps://kktjs.github.io/kkt-ssr/zip/\x1b[0m +`; + +export const helpCli: string = ` + Usage: create-kkt-ssr [options] [--help|h] + + Options: + + --version, -v Show version number + --help, -h Displays help information. + --output, -o Output directory. + --example, -e Example from: \x1b[34mhttps://kktjs.github.io/kkt-ssr/zip/\x1b[0m, default: "kkt-ssr-ts" + --path, -p Specify the download target git address. + default: "\x1b[34mhttps://kktjs.github.io/kkt-ssr/zip/\x1b[0m" + + ${helpExample} + + Copyright 2022 + +`; diff --git a/packages/create-kkt-ssr/test/cli.test.ts b/packages/create-kkt-ssr/test/cli.test.ts new file mode 100644 index 0000000..2e795b3 --- /dev/null +++ b/packages/create-kkt-ssr/test/cli.test.ts @@ -0,0 +1,49 @@ +/** @jest-environment node */ +import fs from 'fs-extra'; +import path from 'path'; +import pkg from '../package.json'; +import { helpCli, run, helpExample } from '../src/utils'; + +it('help test case.', async () => { + expect(typeof helpExample).toEqual('string'); + expect(typeof helpCli).toEqual('string'); +}); + +it('help test case.', async () => { + const mockExit = jest.spyOn(console, 'log').mockImplementation(); + process.argv = process.argv.slice(0, 2); + process.argv.push('my-app3'); + process.argv.push('--help'); + await import('../src/cli'); + expect(mockExit).toHaveBeenCalledWith(helpCli); + mockExit.mockRestore(); + mockExit.mockClear(); + mockExit.mockReset(); +}); + +it('version test case.', async () => { + const mockExit = jest.spyOn(console, 'log').mockImplementation(); + process.argv = process.argv.slice(0, 2); + process.argv.push('my-app4'); + process.argv.push('--version'); + await run(); + // @ts-ignore + expect(mockExit).toHaveBeenCalledWith( + `\n create-uiw-admin v${pkg.version}\n`, + ); + mockExit.mockRestore(); + mockExit.mockClear(); + mockExit.mockReset(); +}); + +it('create project. 1', async () => { + console.log = jest.fn(); + process.argv = process.argv.slice(0, 2); + process.argv.push('my-app2'); + process.argv.push('-f'); + process.argv.push('--output'); + process.argv.push('test'); + await run(); + expect(await fs.existsSync(path.resolve(__dirname, 'my-app2'))).toBeTruthy(); + await fs.remove('test/my-app2'); +}, 10000); diff --git a/packages/create-kkt-ssr/tsconfig.json b/packages/create-kkt-ssr/tsconfig.json new file mode 100644 index 0000000..9663314 --- /dev/null +++ b/packages/create-kkt-ssr/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "declaration": true, + "target": "es2017", + "noImplicitAny": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "strict": false, + "skipLibCheck": true, + "outDir": "lib", + "baseUrl": "." + }, + "include": ["src/**/*"] +} diff --git a/packages/react-ssr-enhanced/package.json b/packages/react-ssr-enhanced/package.json index e800ec8..b22dd21 100644 --- a/packages/react-ssr-enhanced/package.json +++ b/packages/react-ssr-enhanced/package.json @@ -1,12 +1,12 @@ { "name": "@kkt/react-ssr-enhanced", - "version": "2.0.2", + "version": "3.0.1", "description": "KKT react server side rendering enhancement tool.", - "main": "lib/cjs/index.js", - "module": "lib/esm/index.js", + "main": "lib/index.js", + "module": "esm/index.js", "scripts": { - "watch": "tsbb watch --target react", - "build": "tsbb build --target react" + "watch": "tsbb watch", + "build": "tsbb build" }, "keywords": [ "kkt", @@ -31,12 +31,13 @@ "react": "17.0.2", "react-dom": "17.0.2", "react-helmet": "6.1.0", - "react-redux": "5.1.1", + "react-redux": "7.2.6", "react-router-dom": "^4.3.1", - "redux": "^4.0.4", - "serialize-javascript": "6.0.0" + "redux": "4.1.2", + "serialize-javascript": "6.0.0", + "url": "0.11.0" }, "devDependencies": { "tsbb": "3.7.0" } -} \ No newline at end of file +}