├── dev.md ├── example ├── uma-css-module │ ├── .eslintignore │ ├── README.md │ ├── .gitignore │ ├── web │ │ ├── common.less │ │ ├── pages │ │ │ ├── css-demo │ │ │ │ ├── index.module.css │ │ │ │ └── index.tsx │ │ │ ├── less-demo │ │ │ │ ├── index.module.less │ │ │ │ └── index.tsx │ │ │ └── scss-demo │ │ │ │ ├── index.module.scss │ │ │ │ └── index.tsx │ │ ├── global.d.ts │ │ ├── tsconfig.json │ │ └── index.html │ ├── src │ │ ├── app.ts │ │ ├── config │ │ │ └── plugin.config.ts │ │ └── controller │ │ │ └── index.controller.ts │ ├── tsconfig.json │ ├── .vscode │ │ └── launch.json │ └── package.json ├── uma-useContext-useReducer │ ├── .eslintignore │ ├── web │ │ ├── global.d.ts │ │ ├── @types │ │ │ └── global.d.ts │ │ ├── context.tsx │ │ ├── interface │ │ │ ├── index.ts │ │ │ ├── page-index.ts │ │ │ └── detail-index.ts │ │ ├── components │ │ │ ├── slider │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── player │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── recommend │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── rectangle │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── search │ │ │ │ ├── index.module.less │ │ │ │ └── index.tsx │ │ │ └── brief │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ ├── pages │ │ │ ├── detail │ │ │ │ ├── test.tsx │ │ │ │ └── index.tsx │ │ │ └── index │ │ │ │ └── index.tsx │ │ ├── hooks │ │ │ └── useContextHooks.tsx │ │ ├── common.less │ │ └── index.html │ ├── .gitignore │ ├── README.md │ ├── src │ │ ├── app.ts │ │ ├── plugins │ │ │ └── error │ │ │ │ └── index.ts │ │ ├── config │ │ │ └── plugin.config.ts │ │ └── controller │ │ │ └── index.controller.ts │ ├── tsconfig.json │ ├── .vscode │ │ └── launch.json │ └── package.json └── uma-react-redux │ ├── README.md │ ├── web │ └── pages │ │ └── index │ │ ├── features │ │ └── counter │ │ │ ├── counterAPI.js │ │ │ ├── counterSlice.spec.js │ │ │ ├── Counter.module.css │ │ │ └── Counter.js │ │ ├── app │ │ └── store.js │ │ ├── index.js │ │ ├── index.css │ │ ├── App.css │ │ ├── logo.svg │ │ └── App.js │ ├── src │ ├── config │ │ ├── plugin.config.ts │ │ └── status.config.ts │ ├── app.ts │ └── controller │ │ └── index.controller.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── .vscode │ └── launch.json │ ├── package.json │ └── .eslintrc.js ├── packages ├── app-vue │ ├── web │ │ ├── component │ │ │ ├── foo.css │ │ │ ├── ImportType.vue │ │ │ └── Foo.jsx │ │ ├── pages │ │ │ ├── vue │ │ │ │ ├── index.module.less │ │ │ │ ├── index.less │ │ │ │ └── index.js │ │ │ ├── vuex │ │ │ │ ├── index.js │ │ │ │ └── app.vue │ │ │ └── index │ │ │ │ ├── home.vue │ │ │ │ ├── about.vue │ │ │ │ ├── App.vue │ │ │ │ ├── index.js │ │ │ │ └── index.html │ │ ├── images │ │ │ └── srejs.png │ │ └── store │ │ │ └── index.js │ ├── start.js │ ├── .eslintrc │ ├── package.json │ └── app.js ├── app-vue3 │ ├── config │ │ └── ssr.config.js │ ├── web │ │ ├── pages │ │ │ ├── vue │ │ │ │ ├── index.module.less │ │ │ │ ├── index.less │ │ │ │ └── index.js │ │ │ ├── vuex │ │ │ │ ├── index.js │ │ │ │ └── app.vue │ │ │ └── index │ │ │ │ ├── App.vue │ │ │ │ ├── about.vue │ │ │ │ ├── home.vue │ │ │ │ ├── index.js │ │ │ │ └── index.html │ │ ├── images │ │ │ └── srejs.png │ │ └── store │ │ │ └── index.js │ ├── start.js │ ├── .eslintrc │ ├── package.json │ └── app.js ├── app │ ├── web │ │ ├── .DS_Store │ │ ├── favicon.ico │ │ ├── images │ │ │ ├── .DS_Store │ │ │ └── srejs.png │ │ ├── pages │ │ │ ├── modules │ │ │ │ ├── index.module.less │ │ │ │ └── index.tsx │ │ │ ├── redux │ │ │ │ ├── index.js │ │ │ │ ├── page │ │ │ │ │ ├── UseEffect01.js │ │ │ │ │ ├── UseState01.js │ │ │ │ │ ├── UseState02.js │ │ │ │ │ ├── UseState03.js │ │ │ │ │ ├── UseEffect04.js │ │ │ │ │ ├── UseEffect03.js │ │ │ │ │ ├── UseEffect02.js │ │ │ │ │ ├── UseReducer.js │ │ │ │ │ └── UseContext.js │ │ │ │ ├── action │ │ │ │ │ └── timeAction.js │ │ │ │ ├── reducer │ │ │ │ │ └── timeReducer.js │ │ │ │ └── redux.scss │ │ │ ├── ruleHistoryList │ │ │ │ ├── index.less │ │ │ │ └── index.html │ │ │ ├── index │ │ │ │ ├── fool.ts │ │ │ │ ├── index.html │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── detail │ │ │ │ └── index.tsx │ │ │ ├── list │ │ │ │ ├── index.html │ │ │ │ ├── index.tsx │ │ │ │ └── index.scss │ │ │ └── router │ │ │ │ ├── index.js │ │ │ │ └── index.scss │ │ ├── @types │ │ │ ├── global.d.ts │ │ │ └── ruleHistory.ts │ │ ├── layout │ │ │ ├── index.scss │ │ │ └── index.js │ │ ├── enum │ │ │ └── ruleHistory.ts │ │ ├── typed-css.d.ts │ │ └── tsconfig.json │ ├── start.js │ ├── webpack.config.js │ ├── .eslintrc │ └── package.json ├── vue │ ├── src │ │ ├── build.js │ │ ├── dev.js │ │ ├── send-html.js │ │ └── index.d.ts │ ├── .babelrc │ ├── .eslintrc │ ├── bin │ │ └── index.js │ └── package.json ├── vue3 │ ├── src │ │ ├── build.js │ │ ├── dev.js │ │ ├── send-html.js │ │ └── index.d.ts │ ├── .babelrc │ ├── .eslintrc │ ├── bin │ │ └── index.js │ └── package.json ├── react │ ├── src │ │ ├── build.js │ │ ├── dev.js │ │ ├── send-html.js │ │ ├── index.d.ts │ │ └── initialProps.js │ ├── .babelrc │ ├── bin │ │ └── index.js │ ├── .eslintrc │ └── package.json ├── common │ ├── src │ │ ├── log │ │ │ └── index.js │ │ ├── index.js │ │ ├── common.js │ │ ├── spinner.js │ │ └── spinnerProcess.js │ ├── .babelrc │ ├── .eslintrc │ └── package.json ├── react-webpack │ ├── src │ │ ├── react │ │ │ ├── dev.js │ │ │ ├── prod.js │ │ │ ├── combine.js │ │ │ ├── server.js │ │ │ ├── index.html │ │ │ └── hot.js │ │ └── index.js │ ├── .babelrc │ └── .eslintrc ├── vue-webpack │ ├── src │ │ ├── vue │ │ │ ├── dev.js │ │ │ ├── prod.js │ │ │ ├── index.html │ │ │ ├── combine.js │ │ │ ├── server.js │ │ │ └── hot.js │ │ └── index.js │ ├── .babelrc │ └── .eslintrc └── vue3-webpack │ ├── src │ ├── vue │ │ ├── dev.js │ │ ├── prod.js │ │ ├── index.html │ │ ├── combine.js │ │ ├── server.js │ │ └── hot.js │ └── index.js │ ├── .babelrc │ └── .eslintrc ├── doc ├── Srejs.png ├── Srejs-vue.png ├── Srejs-react.png ├── react │ ├── Srejs.jpeg │ ├── cssModules.md │ ├── htmlTemplate.md │ ├── webpackconfig.md │ ├── typescript.md │ ├── initprops.md │ └── page-router.md ├── vue │ ├── vue-router.md │ ├── vuex.md │ ├── seoHtml.md │ └── suport-css.md └── vue3 │ ├── vue-router.md │ ├── vuex.md │ ├── seoHtml.md │ └── suport-css.md ├── .gitignore ├── lerna.json ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE └── package.json /dev.md: -------------------------------------------------------------------------------- 1 | ## 开始 2 | ```shell 3 | yarn 4 | 5 | F5 启动调试 6 | ``` 7 | -------------------------------------------------------------------------------- /example/uma-css-module/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | .ssr 3 | node_modules 4 | -------------------------------------------------------------------------------- /packages/app-vue/web/component/foo.css: -------------------------------------------------------------------------------- 1 | .jsx { 2 | color: blue; 3 | } -------------------------------------------------------------------------------- /doc/Srejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/doc/Srejs.png -------------------------------------------------------------------------------- /doc/Srejs-vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/doc/Srejs-vue.png -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | .ssr 3 | node_modules 4 | -------------------------------------------------------------------------------- /doc/Srejs-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/doc/Srejs-react.png -------------------------------------------------------------------------------- /doc/react/Srejs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/doc/react/Srejs.jpeg -------------------------------------------------------------------------------- /packages/app-vue3/config/ssr.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | version: '3' 3 | }; 4 | -------------------------------------------------------------------------------- /packages/app/web/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app/web/.DS_Store -------------------------------------------------------------------------------- /packages/app-vue/web/pages/vue/index.module.less: -------------------------------------------------------------------------------- 1 | .module{ 2 | color: red; 3 | font-size: 36px; 4 | } -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/vue/index.module.less: -------------------------------------------------------------------------------- 1 | .module{ 2 | color: red; 3 | font-size: 36px; 4 | } -------------------------------------------------------------------------------- /packages/app/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app/web/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | dist 4 | .ssr 5 | packages/app/.DS_Store 6 | .DS_Store 7 | packages-lock.json 8 | -------------------------------------------------------------------------------- /packages/app/web/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app/web/images/.DS_Store -------------------------------------------------------------------------------- /packages/app/web/images/srejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app/web/images/srejs.png -------------------------------------------------------------------------------- /packages/app-vue/web/images/srejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app-vue/web/images/srejs.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "npmClient": "yarn", 6 | "version": "1.4.2" 7 | } 8 | -------------------------------------------------------------------------------- /packages/app-vue3/web/images/srejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazjean/Srejs/HEAD/packages/app-vue3/web/images/srejs.png -------------------------------------------------------------------------------- /packages/app/web/pages/modules/index.module.less: -------------------------------------------------------------------------------- 1 | .home{ 2 | color: red; 3 | font-size: 25px; 4 | } 5 | .text{ 6 | color: black; 7 | } -------------------------------------------------------------------------------- /packages/app/web/pages/redux/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import './redux.scss'; 3 | import APP from './page/UseState01'; 4 | 5 | export default APP; 6 | -------------------------------------------------------------------------------- /packages/vue/src/build.js: -------------------------------------------------------------------------------- 1 | import { WebpackVue } from '@srejs/vue-webpack'; 2 | export const build = async (page = true) => { 3 | WebpackVue.build(page); 4 | }; 5 | -------------------------------------------------------------------------------- /example/uma-css-module/README.md: -------------------------------------------------------------------------------- 1 | ## 开发 2 | ```shell 3 | yarn start 4 | ``` 5 | 6 | **更多插件配置和使用方法请查看[`@umajs/plugin-react-ssr`](https://github.com/Umajs/plugin-react-ssr)** -------------------------------------------------------------------------------- /example/uma-react-redux/README.md: -------------------------------------------------------------------------------- 1 | ## 开发 2 | ```shell 3 | yarn start 4 | ``` 5 | 6 | **更多插件配置和使用方法请查看[`@umajs/plugin-react-ssr`](https://github.com/Umajs/plugin-react-ssr)** -------------------------------------------------------------------------------- /packages/app-vue/web/pages/vue/index.less: -------------------------------------------------------------------------------- 1 | .import-css{ 2 | color: red; 3 | font-size: 36px; 4 | } 5 | #app{ 6 | background-image :url("@/images/srejs.png") 7 | } -------------------------------------------------------------------------------- /packages/vue3/src/build.js: -------------------------------------------------------------------------------- 1 | import { WebpackVue } from '@srejs/vue3-webpack'; 2 | export const build = async (page = true) => { 3 | WebpackVue.build(page); 4 | }; 5 | -------------------------------------------------------------------------------- /packages/app/web/@types/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare global { 4 | interface Window { 5 | __SSR_DATA__:any 6 | } 7 | } 8 | export {}; 9 | -------------------------------------------------------------------------------- /packages/app/web/layout/index.scss: -------------------------------------------------------------------------------- 1 | .layout { 2 | padding-top: 20px; 3 | .title { 4 | background-color: antiquewhite; 5 | font-size: 20px; 6 | } 7 | } -------------------------------------------------------------------------------- /packages/react/src/build.js: -------------------------------------------------------------------------------- 1 | import { WebpackReact } from '@srejs/react-webpack'; 2 | export const build = async (page = true) => { 3 | WebpackReact.build(page); 4 | }; 5 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/vue/index.less: -------------------------------------------------------------------------------- 1 | .import-css{ 2 | color: red; 3 | font-size: 36px; 4 | } 5 | #app{ 6 | background-image :url("@/images/srejs.png") no-repeat; 7 | } -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare global { 3 | interface Window { 4 | __SSR_DATA__:any 5 | } 6 | } 7 | 8 | export {}; 9 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/vuex/index.js: -------------------------------------------------------------------------------- 1 | import App from './app.vue'; 2 | import { vuexStore as Store } from '@/store/index'; 3 | 4 | export default { 5 | App, 6 | Store 7 | }; 8 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/vuex/index.js: -------------------------------------------------------------------------------- 1 | import App from './app.vue'; 2 | import { vuexStore as Store } from '@/store/index'; 3 | 4 | export default { 5 | App, 6 | Store 7 | }; 8 | -------------------------------------------------------------------------------- /packages/app/web/enum/ruleHistory.ts: -------------------------------------------------------------------------------- 1 | type TRuleType = { 2 | [key:number]:string 3 | } 4 | export const RULETYPE:TRuleType = { 5 | 0: '全部', 6 | 1: '交易规则', 7 | 2: '账户规则', 8 | }; 9 | -------------------------------------------------------------------------------- /packages/app-vue/web/component/ImportType.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /packages/app-vue/start.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | presets: ['@babel/env'] 3 | }); 4 | require('core-js/stable'); 5 | require('regenerator-runtime'); 6 | module.exports = require('./app.js'); 7 | -------------------------------------------------------------------------------- /packages/app-vue3/start.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | presets: ['@babel/env'] 3 | }); 4 | require('core-js/stable'); 5 | require('regenerator-runtime'); 6 | module.exports = require('./app.js'); 7 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/@types/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare global { 4 | interface Window { 5 | __SSR_DATA__:any 6 | } 7 | } 8 | 9 | export {}; 10 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/vue/index.js: -------------------------------------------------------------------------------- 1 | import App from './App.vue'; 2 | 3 | export default { 4 | App, 5 | Store: { 6 | state: { 7 | say: 'hello!' 8 | } 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/vue/index.js: -------------------------------------------------------------------------------- 1 | import App from './App.vue'; 2 | 3 | export default { 4 | App, 5 | Store: { 6 | state: { 7 | say: 'hello!' 8 | } 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /example/uma-css-module/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .cache 3 | node_modules 4 | .DS_Store 5 | dist 6 | lib 7 | app 8 | /node_modules 9 | .history/ 10 | logs/ 11 | yarn-error.log 12 | yarn.lock 13 | package-lock.json 14 | .ssr/ -------------------------------------------------------------------------------- /packages/app/start.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | presets: ['@babel/env', '@babel/react'] 3 | }); 4 | require('core-js/stable'); 5 | require('regenerator-runtime/runtime'); 6 | module.exports = require('./app.js'); 7 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .cache 3 | node_modules 4 | .DS_Store 5 | dist 6 | lib 7 | app 8 | /node_modules 9 | .history/ 10 | logs/ 11 | yarn-error.log 12 | yarn.lock 13 | package-lock.json 14 | .ssr/ -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { MixStateAndDispatch } from './interface'; 3 | 4 | const Context = React.createContext>({ state: {} }); 5 | 6 | export default Context; 7 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/features/counter/counterAPI.js: -------------------------------------------------------------------------------- 1 | // A mock function to mimic making an async request for data 2 | export function fetchCount(amount = 1) { 3 | return new Promise((resolve) => 4 | setTimeout(() => resolve({ data: amount }), 500) 5 | ); 6 | } 7 | -------------------------------------------------------------------------------- /packages/app/web/pages/ruleHistoryList/index.less: -------------------------------------------------------------------------------- 1 | #app{ 2 | margin: 10px; 3 | } 4 | 5 | .coustom-divider{ 6 | .ant-divider-inner-text{ 7 | border-bottom: solid; 8 | border-color: #ff5a37; 9 | } 10 | } 11 | .ant-tabs-tabpane{ 12 | padding: 20px; 13 | } -------------------------------------------------------------------------------- /packages/common/src/log/index.js: -------------------------------------------------------------------------------- 1 | import { getCoreConfig } from '../config'; 2 | const { log } = getCoreConfig(); 3 | export let Logger = console; 4 | if (!log) { 5 | ['info', 'warn', 'error', 'debug', 'log'].forEach((action) => { 6 | Logger[action] = () => {}; 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/dev.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import combine from './combine'; 3 | 4 | export function getDevConfig(page, isServer, hotReload = false) { 5 | let config = getBaseconfig(page, isServer, hotReload); 6 | return combine(config, false); 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/dev.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import combine from './combine'; 3 | 4 | export function getDevConfig(page, isServer, hotReload = false) { 5 | let config = getBaseconfig(page, isServer, hotReload); 6 | return combine(config, false); 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/dev.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import combine from './combine'; 3 | 4 | export function getDevConfig(page, isServer, hotReload = false) { 5 | let config = getBaseconfig(page, isServer, hotReload); 6 | return combine(config, false); 7 | } 8 | -------------------------------------------------------------------------------- /example/uma-css-module/web/common.less: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | a { 7 | color: #fff; 8 | // text-decoration: none; 9 | } 10 | 11 | ul { 12 | list-style: none; 13 | } 14 | html,body,#app{ 15 | font-size: 100px; 16 | height: 100%; 17 | width: 100%; 18 | } 19 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/README.md: -------------------------------------------------------------------------------- 1 | > 为了和业内解决方案进行对比,此example页面组件代码来源于[midway-react-ssr](https://github.com/ykfe/ssr/tree/dev/example/midway-react-ssr) 2 | 3 | 4 | ## 开发 5 | ```shell 6 | yarn start 7 | ``` 8 | 9 | **更多插件配置和使用方法请查看[`@umajs/plugin-react-ssr`](https://github.com/Umajs/plugin-react-ssr)** -------------------------------------------------------------------------------- /example/uma-react-redux/src/config/plugin.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'react-ssr': { 3 | enable: true, 4 | options: { 5 | rootDir: 'web', 6 | ssr: true, // 全局开启服务端渲染 7 | cache: false, // 全局使用服务端渲染缓存 开发环境设置true无效 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/uma-css-module/src/app.ts: -------------------------------------------------------------------------------- 1 | import Uma from '@umajs/core'; 2 | import { Router } from '@umajs/router'; 3 | 4 | const uma = Uma.instance({ 5 | Router, 6 | ROOT: __dirname, 7 | env: process.argv.indexOf('--production') > -1 ? 'production' : 'development', 8 | }); 9 | 10 | uma.start(8058); 11 | -------------------------------------------------------------------------------- /packages/app-vue/web/component/Foo.jsx: -------------------------------------------------------------------------------- 1 | import { defineComponent } from 'vue'; 2 | import './foo.css'; 3 | 4 | // named exports w/ variable declaration: ok 5 | export const Foo = defineComponent({ 6 | name: 'foo', 7 | setup() { 8 | return () =>
from JSX
; 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /packages/app/web/pages/index/fool.ts: -------------------------------------------------------------------------------- 1 | export const TreeSharkingA = 'TreeSharkingA'; 2 | export const TreeSharkingB = 'TreeSharkingB'; 3 | 4 | export function testTreeSharkingA() { 5 | console.log(TreeSharkingA); 6 | } 7 | 8 | export function testTreeSharkingB() { 9 | console.log(TreeSharkingB); 10 | } 11 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/src/app.ts: -------------------------------------------------------------------------------- 1 | import Uma from '@umajs/core'; 2 | import { Router } from '@umajs/router'; 3 | 4 | const uma = Uma.instance({ 5 | Router, 6 | ROOT: __dirname, 7 | env: process.argv.indexOf('--production') > -1 ? 'production' : 'development', 8 | }); 9 | 10 | uma.start(8058); 11 | -------------------------------------------------------------------------------- /packages/app/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = (configureWebpack, type) => { 2 | if (type == 'ssr') { 3 | //服务端渲染配置 4 | } else if (type === 'csr') { 5 | //客户端构建配置 6 | // configureWebpack.module.rules[0].exclude = /\/node_module\/!(antd.*)/; 7 | } 8 | 9 | return configureWebpack; 10 | }; 11 | -------------------------------------------------------------------------------- /example/uma-react-redux/src/app.ts: -------------------------------------------------------------------------------- 1 | import Uma from '@umajs/core'; 2 | import { Router } from '@umajs/router'; 3 | 4 | const uma = Uma.instance({ 5 | Router, 6 | bodyParser: { multipart: true }, 7 | ROOT: __dirname, 8 | env: process.argv.indexOf('--production') > -1 ? 'production' : 'development', 9 | }); 10 | 11 | uma.start(8058); 12 | -------------------------------------------------------------------------------- /example/uma-react-redux/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .cache 3 | node_modules 4 | .DS_Store 5 | dist 6 | lib 7 | /app 8 | /node_modules 9 | lerna-debug.log 10 | /packages/*/*/*/*.log 11 | .history/ 12 | packages/plugin-logger/__tests__/app/src/logs/ 13 | packages/logger/__tests__/__mocks__/log/ 14 | packages/app/logs/home.log 15 | yarn-error.log 16 | yarn.lock 17 | package-lock.json -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/app/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import counterReducer from '../features/counter/counterSlice'; 3 | 4 | 5 | export const createStore = (Props)=>{ 6 | return configureStore({ 7 | reducer: { 8 | counter: counterReducer, 9 | }, 10 | preloadedState:{counter:Props.counter} 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /packages/common/src/index.js: -------------------------------------------------------------------------------- 1 | export { Logger } from './log'; 2 | export { isDev, getOptions, setOptions } from './common'; 3 | export * from './config'; 4 | export * from './util'; 5 | import { isDev, getOptions, setOptions } from './common'; 6 | export { spinner } from './spinnerProcess'; 7 | 8 | export default { 9 | isDev, 10 | getOptions, 11 | setOptions 12 | }; 13 | -------------------------------------------------------------------------------- /example/uma-react-redux/src/config/status.config.ts: -------------------------------------------------------------------------------- 1 | import { IContext } from '@umajs/core'; 2 | 3 | /* eslint-disable no-underscore-dangle */ 4 | export default { 5 | _404(ctx: IContext) { 6 | return ctx.render('404.html'); 7 | }, 8 | _error(e: Error, ctx: IContext) { 9 | console.log(e); 10 | 11 | return ctx.send('500 ERROR'); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /example/uma-css-module/src/config/plugin.config.ts: -------------------------------------------------------------------------------- 1 | import { TPluginConfig } from '@umajs/core'; 2 | 3 | export default <{ [key: string]: TPluginConfig }>{ 4 | 'react-ssr': { 5 | enable: true, 6 | options: { 7 | rootDir: 'web', 8 | ssr: true, // 全局开启服务端渲染 9 | cache: false, // 全局使用服务端渲染缓存 开发环境设置true无效 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /example/uma-react-redux/src/controller/index.controller.ts: -------------------------------------------------------------------------------- 1 | import { BaseController ,Path} from '@umajs/core'; 2 | import { Result } from '@umajs/plugin-react-ssr' 3 | 4 | @Path('/') 5 | export default class Index extends BaseController { 6 | @Path() 7 | index() { 8 | return Result.reactView('index',{counter:{value: 3, 9 | status: 'idle',amount:5}}); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/interface/index.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export * from './page-index'; 4 | export * from './detail-index'; 5 | export type ActionType = { 6 | type: string, 7 | payload:{ 8 | [key:string]:any 9 | } 10 | } 11 | 12 | export type MixStateAndDispatch = { 13 | state: T, 14 | dispatch?: React.Dispatch 15 | } 16 | -------------------------------------------------------------------------------- /packages/app/web/pages/modules/index.tsx: -------------------------------------------------------------------------------- 1 | import style from './index.module.less'; 2 | import React from 'react'; 3 | type typeProps = { 4 | msg: string; 5 | }; 6 | export default function (props: typeProps) { 7 | return ( 8 |
9 |

css modules

10 |
{props.msg}
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './index.css'; 3 | import App from './App'; 4 | import { createStore } from './app/store'; 5 | import { Provider } from 'react-redux'; 6 | 7 | export default (Props)=>{ 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /packages/app/web/@types/ruleHistory.ts: -------------------------------------------------------------------------------- 1 | export type TRuleItem = { 2 | fileName?:string, 3 | startTime?:string, 4 | endTime?:string, 5 | dStartTime?:string, 6 | dEndTime?:string, 7 | ruleType?:number, 8 | id?:number, 9 | filePath?:string|any, 10 | status:number 11 | } 12 | 13 | export type TRuleHistoryData = { 14 | code:number, 15 | message:string, 16 | list:[TRuleItem] 17 | } 18 | -------------------------------------------------------------------------------- /packages/app-vue/web/store/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue'; 2 | // import Vuex from 'vuex'; 3 | 4 | // Vue.use(Vuex); 5 | // export function createStore() { 6 | // return new Vuex.Store(); 7 | // } 8 | 9 | export const vuexStore = { 10 | state: { 11 | count: 100 12 | }, 13 | mutations: { 14 | increment: (state) => state.count++, 15 | decrement: (state) => state.count-- 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/index/home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/app-vue3/web/store/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue'; 2 | // import Vuex from 'vuex'; 3 | 4 | // Vue.use(Vuex); 5 | // export function createStore() { 6 | // return new Vuex.Store(); 7 | // } 8 | 9 | export const vuexStore = { 10 | state: { 11 | count: 100 12 | }, 13 | mutations: { 14 | increment: (state) => state.count++, 15 | decrement: (state) => state.count-- 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /packages/app/web/pages/detail/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | type typeProps = { 3 | detail: { 4 | text: string; 5 | }; 6 | }; 7 | export default function (props: typeProps) { 8 | const { detail } = props; 9 | return ( 10 |
11 |

detail

12 |
{detail.text}
13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/css-demo/index.module.css: -------------------------------------------------------------------------------- 1 | .home{ 2 | background-color: black; 3 | color: #ffffff; 4 | font-size: 16px; 5 | text-align: center; 6 | height: 100%; 7 | display: flex; 8 | align-items: center; 9 | flex-direction: column; 10 | justify-content: center; 11 | } 12 | .title{ 13 | font-size: 40px; 14 | font-weight: bold; 15 | } 16 | 17 | .des{ 18 | font-size: 18px; 19 | } -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/less-demo/index.module.less: -------------------------------------------------------------------------------- 1 | .home{ 2 | background-color: black; 3 | color: #ffffff; 4 | font-size: 16px; 5 | text-align: center; 6 | height: 100%; 7 | display: flex; 8 | align-items: center; 9 | flex-direction: column; 10 | justify-content: center; 11 | } 12 | .title{ 13 | font-size: 40px; 14 | font-weight: bold; 15 | } 16 | 17 | .des{ 18 | font-size: 18px; 19 | } -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/scss-demo/index.module.scss: -------------------------------------------------------------------------------- 1 | .home{ 2 | background-color: black; 3 | color: #ffffff; 4 | font-size: 16px; 5 | text-align: center; 6 | height: 100%; 7 | display: flex; 8 | align-items: center; 9 | flex-direction: column; 10 | justify-content: center; 11 | } 12 | .title{ 13 | font-size: 40px; 14 | font-weight: bold; 15 | } 16 | 17 | .des{ 18 | font-size: 18px; 19 | } -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/src/plugins/error/index.ts: -------------------------------------------------------------------------------- 1 | import * as Koa from 'koa'; 2 | import { Uma, IContext } from '@umajs/core'; 3 | 4 | export type Options = {}; 5 | 6 | export default (_uma: Uma, _options: Options = {}): Koa.Middleware => async (ctx: IContext, next: Function) => { 7 | try { 8 | await next(); 9 | } catch (e) { 10 | return ctx.reactView('error', { msg: e }, { cache: false }); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/index/about.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /example/uma-css-module/web/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare global { 3 | interface Window { 4 | __SSR_DATA__:any 5 | } 6 | } 7 | 8 | declare module '*.module.less' { 9 | const classes: { [key: string]: string }; 10 | export default classes; 11 | } 12 | 13 | declare module '*.module.scss' { 14 | const classes: { [key: string]: string }; 15 | export default classes; 16 | } 17 | 18 | declare module 'react-dom' 19 | export {}; 20 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /example/uma-css-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2017", 5 | "noImplicitAny": false, 6 | "sourceMap": false, 7 | "rootDir":"./src", 8 | "outDir":"./app", 9 | "watch":false, 10 | "alwaysStrict": true, 11 | "removeComments": true, 12 | "preserveWatchOutput": true, 13 | "experimentalDecorators": true 14 | }, 15 | "include":[ 16 | "./src/**/*" 17 | ] 18 | } -------------------------------------------------------------------------------- /example/uma-react-redux/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2017", 5 | "noImplicitAny": false, 6 | "sourceMap": false, 7 | "rootDir":"./src", 8 | "outDir":"./app", 9 | "watch":false, 10 | "alwaysStrict": true, 11 | "removeComments": true, 12 | "preserveWatchOutput": true, 13 | "experimentalDecorators": true 14 | }, 15 | "include":[ 16 | "./src/**/*" 17 | ] 18 | } -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2017", 5 | "noImplicitAny": false, 6 | "sourceMap": false, 7 | "rootDir":"./src", 8 | "outDir":"./app", 9 | "watch":false, 10 | "alwaysStrict": true, 11 | "removeComments": true, 12 | "preserveWatchOutput": true, 13 | "experimentalDecorators": true 14 | }, 15 | "include":[ 16 | "./src/**/*" 17 | ] 18 | } -------------------------------------------------------------------------------- /packages/vue-webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":[[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ], 20 | "ignore":["src/vue/app.js"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue3-webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":[[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ], 20 | "ignore":["src/vue/app.js"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/prod.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import { getPlugin } from './plugin'; 3 | import combine from './combine'; 4 | 5 | function getProconfig(page, isServer) { 6 | let config = getBaseconfig(page); 7 | 8 | let buildConfig = Object.assign({}, config, { 9 | devtool: false, 10 | mode: 'production', 11 | plugins: [...getPlugin(config.entry, isServer)] 12 | }); 13 | return combine(buildConfig, false); 14 | } 15 | 16 | module.exports = { 17 | getProconfig 18 | }; 19 | -------------------------------------------------------------------------------- /packages/vue/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":[[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/prod.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import { getPlugin } from './plugin'; 3 | import combine from './combine'; 4 | 5 | function getProconfig(page, isServer) { 6 | let config = getBaseconfig(page); 7 | 8 | let buildConfig = Object.assign({}, config, { 9 | devtool: false, 10 | mode: 'production', 11 | plugins: [...getPlugin(config.entry, isServer)] 12 | }); 13 | return combine(buildConfig, false); 14 | } 15 | 16 | module.exports = { 17 | getProconfig 18 | }; 19 | -------------------------------------------------------------------------------- /packages/vue3/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":[[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/common/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":[[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/react-webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["@babel/react",[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ], 20 | "ignore":["src/react/app.js"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/prod.js: -------------------------------------------------------------------------------- 1 | import { getBaseconfig } from './base'; 2 | import { getPlugin } from './plugin'; 3 | import combine from './combine'; 4 | 5 | function getProconfig(page, isServer) { 6 | let config = getBaseconfig(page); 7 | 8 | let buildConfig = Object.assign({}, config, { 9 | devtool: false, 10 | mode: 'production', 11 | plugins: [...getPlugin(config.entry, isServer)] 12 | }); 13 | return combine(buildConfig, false); 14 | } 15 | 16 | module.exports = { 17 | getProconfig 18 | }; 19 | -------------------------------------------------------------------------------- /packages/react-webpack/src/index.js: -------------------------------------------------------------------------------- 1 | import Webpack from 'webpack'; 2 | import WebpackDevServer from 'webpack-dev-server'; 3 | 4 | export { Webpack, WebpackDevServer }; 5 | /**React */ 6 | export { Webpack as WebpackReact } from './react/index'; 7 | export { getDevConfig } from './react/dev'; 8 | export { DevMiddlewareFileSystem, Hotwebpack } from './react/hot'; 9 | export { 10 | initEntry, 11 | getEntry, 12 | EntryList, 13 | getEntryList, 14 | EntryFilesMap, 15 | webpackEntry, 16 | webpackEntryMap 17 | } from './react/entry'; 18 | -------------------------------------------------------------------------------- /packages/common/src/common.js: -------------------------------------------------------------------------------- 1 | import { getCoreConfig, setCoreConfig } from './config'; 2 | 3 | export const isDev = () => { 4 | const NODE_ENV = (process.env && process.env.NODE_ENV) || 'development'; 5 | 6 | return NODE_ENV.trim() !== 'production'; 7 | }; 8 | export const setOptions = (options) => { 9 | let coreOptions = Object.assign({}, getCoreConfig(), options); 10 | return setCoreConfig(coreOptions); 11 | }; 12 | export const getOptions = (name) => { 13 | const options = getCoreConfig(); 14 | return options[name] || null; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["@babel/react",[ 3 | "@babel/env", 4 | { 5 | "targets": { 6 | "browsers": ["last 2 versions", "ie >= 7"] 7 | } 8 | } 9 | ]], 10 | "plugins": [ 11 | [ 12 | "@babel/plugin-transform-runtime", 13 | { "helpers": false, "regenerator": true } 14 | ], 15 | ["@babel/plugin-transform-modules-commonjs", { 16 | "allowTopLevelThis": true, 17 | "importInterop":"node" 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseEffect01.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | let APP = () => { 3 | const [count, setCount] = useState(0); 4 | useEffect(() => { 5 | //document.title = `计数是${count}`; 6 | console.log(`useEffect初始渲染${count}`); 7 | }); 8 | return ( 9 |
10 |
11 | Count: {count} 12 |
13 | 14 |
15 | ); 16 | }; 17 | module.exports = APP; 18 | -------------------------------------------------------------------------------- /packages/common/src/spinner.js: -------------------------------------------------------------------------------- 1 | // 感谢yk/fe团队提供的方案 2 | // 单独创建子进程跑 spinner 否则会被后续的 require 占用进程导致 loading 暂停 3 | const spinner = require('ora')('正在构建'); 4 | 5 | process.on('message', (data) => { 6 | const { message, text, color } = data; 7 | if (message === 'start') { 8 | spinner.spinner = 'hearts'; 9 | spinner.start(); 10 | } else if (message === 'stop') { 11 | spinner.stop(); 12 | process.exit(); 13 | } 14 | 15 | if (text) { 16 | spinner.text = text; 17 | } 18 | if (color) { 19 | spinner.color = color; 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/slider/index.less: -------------------------------------------------------------------------------- 1 | 2 | .swiperContainer { 3 | width: 100%; 4 | height: 1.88rem; 5 | margin-bottom: 10px; 6 | font-size: 12px; 7 | } 8 | 9 | .sliderContainer { 10 | position: relative; 11 | width:100%; 12 | height: 1.88rem; 13 | img { 14 | width: 100%; 15 | height: 100%; 16 | } 17 | } 18 | 19 | .sliderDescContainer { 20 | display: flex; 21 | flex-direction: column; 22 | position: absolute; 23 | bottom: 11px; 24 | left: 12px; 25 | color: #fff; 26 | z-index: 99; 27 | } 28 | .sliderTitle { 29 | font-size: 12px; 30 | } 31 | -------------------------------------------------------------------------------- /packages/app/web/layout/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './index.scss'; 3 | 4 | class index extends Component { 5 | componentDidMount() { 6 | console.log('i am layout !!!!') 7 | } 8 | 9 | render() { 10 | const { children } = this.props 11 | return ( 12 |
13 |
我是通用的header title
14 |
15 | {children} 16 |
17 |
18 | ); 19 | } 20 | } 21 | 22 | export default index; -------------------------------------------------------------------------------- /packages/common/src/spinnerProcess.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { fork } from 'child_process'; 3 | const spinnerProcess = fork(resolve(__dirname, './spinner')); 4 | export const spinner = { 5 | start: () => 6 | spinnerProcess.send({ 7 | message: 'start' 8 | }), 9 | stop: () => 10 | spinnerProcess.send({ 11 | message: 'stop' 12 | }), 13 | text: (text) => 14 | spinnerProcess.send({ 15 | text 16 | }), 17 | color: (color) => 18 | spinnerProcess.send({ 19 | color 20 | }) 21 | }; 22 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/interface/page-index.ts: -------------------------------------------------------------------------------- 1 | export interface IData { 2 | indexData?: IndexData 3 | } 4 | 5 | export interface IndexData { 6 | data: ComponentsArr[] 7 | } 8 | export interface ComponentsArr { 9 | components: ItemMapArr[] 10 | } 11 | 12 | export interface ItemMapArr { 13 | itemMap: ItemMap[] 14 | } 15 | export interface ItemMap { 16 | action: { 17 | type: string 18 | extra: { 19 | value: string 20 | videoId?: string 21 | } 22 | } 23 | mark: { 24 | text: string 25 | } 26 | subtitle?: string 27 | title: string 28 | img: string 29 | summary: string 30 | } 31 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseState01.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | let APP = (initProps) => { 3 | const [count, setCount] = useState(initProps.count || 0); 4 | return ( 5 |
6 |
7 | count: {count} 8 |
9 | 10 | 11 | 12 |
13 | ); 14 | }; 15 | export default APP; 16 | -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/css-demo/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../../common.less'; 3 | import style from './index.module.css'; 4 | 5 | type typeProps = { 6 | des: string; 7 | }; 8 | export default function (props: typeProps) { 9 | return ( 10 |
11 |

css modules

12 |

Srejs按照样式文件名称进行开启和关闭css modules,样式文件规则为:xxx.modules.(less|scss|css)。

13 |
{props.des}
14 | 更多css-modules使用请查看文档 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/less-demo/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../../common.less'; 3 | import style from './index.module.less'; 4 | 5 | type typeProps = { 6 | des: string; 7 | }; 8 | export default function (props: typeProps) { 9 | return ( 10 |
11 |

css modules

12 |

Srejs按照样式文件名称进行开启和关闭css modules,样式文件规则为:xxx.modules.(less|scss|css)。

13 |
{props.des}
14 | 更多css-modules使用请查看文档 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /example/uma-css-module/web/pages/scss-demo/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../../common.less'; 3 | import style from './index.module.scss'; 4 | 5 | type typeProps = { 6 | des: string; 7 | }; 8 | export default function (props: typeProps) { 9 | return ( 10 |
11 |

css modules

12 |

Srejs按照样式文件名称进行开启和关闭css modules,样式文件规则为:xxx.modules.(less|scss|css)。

13 |
{props.des}
14 | 更多css-modules使用请查看文档 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /example/uma-css-module/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Run app", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceRoot}/node_modules/ts-node/dist/bin.js", 12 | "args": [ 13 | "src/app.ts" 14 | ], 15 | "cwd": "${workspaceRoot}", 16 | "protocol": "inspector" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /example/uma-react-redux/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Run app", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceRoot}/node_modules/ts-node/dist/bin.js", 12 | "args": [ 13 | "src/app.ts" 14 | ], 15 | "cwd": "${workspaceRoot}", 16 | "protocol": "inspector" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/src/config/plugin.config.ts: -------------------------------------------------------------------------------- 1 | import { TPluginConfig } from '@umajs/core'; 2 | 3 | export default <{ [key: string]: TPluginConfig }>{ 4 | views: { 5 | enable: true, 6 | name: 'views', 7 | options: { 8 | root: `${process.cwd()}/views`, 9 | autoRender: true, 10 | opts: { 11 | map: { html: 'nunjucks' }, 12 | }, 13 | }, 14 | }, 15 | 'react-ssr': { 16 | enable: true, 17 | options: { 18 | rootDir: 'web', 19 | ssr: true, // 全局开启服务端渲染 20 | cache: false, // 全局使用服务端渲染缓存 开发环境设置true无效 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Run app", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceRoot}/node_modules/ts-node/dist/bin.js", 12 | "args": [ 13 | "src/app.ts" 14 | ], 15 | "cwd": "${workspaceRoot}", 16 | "protocol": "inspector" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /packages/app-vue/web/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import App from './App.vue'; 2 | import About from './about.vue'; 3 | import Home from './home.vue'; 4 | 5 | // route-level code splitting 6 | // const About = () => import('./about.vue'); 7 | // const Home = () => import('./home.vue'); 8 | 9 | export default { 10 | App, 11 | Router: { 12 | mode: 'history', 13 | fallback: false, 14 | base: '/index/', 15 | scrollBehavior: () => ({ y: 0 }), 16 | routes: [ 17 | { path: '/about', props: true, component: About }, 18 | { path: '/home', props: true, component: Home }, 19 | { path: '/', redirect: '/home' } 20 | ] 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /packages/app/web/typed-css.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { [key: string]: string }; 3 | export default classes; 4 | } 5 | 6 | declare module '*.module.scss' { 7 | const classes: { [key: string]: string }; 8 | export default classes; 9 | } 10 | 11 | declare module '*.module.sass' { 12 | const classes: { [key: string]: string }; 13 | export default classes; 14 | } 15 | // less模块声明 16 | declare module '*.module.less' { 17 | const classes: { [key: string]: string }; 18 | export default classes; 19 | } 20 | 21 | declare module '*.module.styl' { 22 | const classes: { [key: string]: string }; 23 | export default classes; 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /doc/react/cssModules.md: -------------------------------------------------------------------------------- 1 | # css modules 2 | > 使用前请查看官方对于css模块化的介绍。[css-modules](https://github.com/css-modules/css-modules) 3 | 4 | 5 | ## 如何使用 6 | > `Srejs`按照样式文件名称进行开启和关闭css modules,样式文件规则为:`xxx.modules.(less|scss|css)`。 7 | 8 | 9 | ### 页面组件 10 | ```ts 11 | import style from './index.module.less'; 12 | import React from 'react'; 13 | type typeProps = { 14 | msg: string; 15 | }; 16 | export default function (props: typeProps) { 17 | return ( 18 |
19 |

css modules

20 |
{props.msg}
21 |
22 | ); 23 | } 24 | ``` 25 | 26 | 27 | ### 样式文件 28 | ```css 29 | .home{ 30 | color:red; 31 | } 32 | ``` -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/src/controller/index.controller.ts: -------------------------------------------------------------------------------- 1 | import { BaseController, Path, Param } from '@umajs/core'; 2 | import { Result } from '@umajs/plugin-react-ssr'; 3 | import ListData from '../mock/index'; 4 | import DetailData from '../mock/detail'; 5 | 6 | @Path('/') 7 | export default class Index extends BaseController { 8 | @Path() 9 | index() { 10 | return Result.reactView('index', { indexData: ListData }, { cache: true }); 11 | } 12 | 13 | @Path('/detail/:id') 14 | detail(@Param('id') id:string) { 15 | return Result.reactView( 16 | 'detail', 17 | { detailData: DetailData.data[id] }, 18 | { cache: false }, 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/react/src/dev.js: -------------------------------------------------------------------------------- 1 | import { getDevConfig, Webpack, WebpackDevServer } from '@srejs/react-webpack'; 2 | export const dev = (page = true) => { 3 | let webpackConfig = getDevConfig(page); 4 | const compiler = Webpack(webpackConfig); 5 | const devServerOptions = Object.assign( 6 | {}, 7 | { 8 | port: '8080', 9 | stats: { 10 | colors: true 11 | } 12 | }, 13 | webpackConfig.devServer 14 | ); 15 | const server = new WebpackDevServer(compiler, devServerOptions); 16 | 17 | server.listen(devServerOptions.port, '127.0.0.1', () => { 18 | console.log('srejs:Starting server on http://localhost:' + devServerOptions.port); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/index.js: -------------------------------------------------------------------------------- 1 | import Webpack from 'webpack'; 2 | import WebpackDevServer from 'webpack-dev-server'; 3 | 4 | export { Webpack, WebpackDevServer }; 5 | /**VUE */ 6 | export { Webpack as WebpackVue } from './vue/index'; 7 | export { getDevConfig as getVueDevConfig } from './vue/dev'; 8 | export { 9 | DevMiddlewareFileSystem as VueDevMiddlewareFileSystem, 10 | Hotwebpack as VueHotWebpack 11 | } from './vue/hot'; 12 | export { 13 | initEntry as initVueEntry, 14 | getEntry as getVueEntry, 15 | EntryList as EntryVueList, 16 | getEntryList as getVueEntryList, 17 | EntryFilesMap as EntryVueFilesMap, 18 | webpackEntry as webpackVueEntry, 19 | webpackEntryMap as webpackVueEntryMap 20 | } from './vue/entry'; 21 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/index.js: -------------------------------------------------------------------------------- 1 | import Webpack from 'webpack'; 2 | import WebpackDevServer from 'webpack-dev-server'; 3 | 4 | export { Webpack, WebpackDevServer }; 5 | /**VUE */ 6 | export { Webpack as WebpackVue } from './vue/index'; 7 | export { getDevConfig as getVueDevConfig } from './vue/dev'; 8 | export { 9 | DevMiddlewareFileSystem as VueDevMiddlewareFileSystem, 10 | Hotwebpack as VueHotWebpack 11 | } from './vue/hot'; 12 | export { 13 | initEntry as initVueEntry, 14 | getEntry as getVueEntry, 15 | EntryList as EntryVueList, 16 | getEntryList as getVueEntryList, 17 | EntryFilesMap as EntryVueFilesMap, 18 | webpackEntry as webpackVueEntry, 19 | webpackEntryMap as webpackVueEntryMap 20 | } from './vue/entry'; 21 | -------------------------------------------------------------------------------- /packages/vue/src/dev.js: -------------------------------------------------------------------------------- 1 | import { getVueDevConfig as getDevConfig, Webpack, WebpackDevServer } from '@srejs/vue-webpack'; 2 | export const dev = (page = true) => { 3 | let webpackConfig = getDevConfig(page); 4 | const compiler = Webpack(webpackConfig); 5 | const devServerOptions = Object.assign( 6 | {}, 7 | { 8 | port: '8080', 9 | stats: { 10 | colors: true 11 | } 12 | }, 13 | webpackConfig.devServer 14 | ); 15 | const server = new WebpackDevServer(compiler, devServerOptions); 16 | 17 | server.listen(devServerOptions.port, '127.0.0.1', () => { 18 | console.log('srejs:Starting server on http://localhost:' + devServerOptions.port); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 26 | 27 | -------------------------------------------------------------------------------- /packages/vue3/src/dev.js: -------------------------------------------------------------------------------- 1 | import { getVueDevConfig as getDevConfig, Webpack, WebpackDevServer } from '@srejs/vue3-webpack'; 2 | export const dev = (page = true) => { 3 | let webpackConfig = getDevConfig(page); 4 | const compiler = Webpack(webpackConfig); 5 | const devServerOptions = Object.assign( 6 | {}, 7 | { 8 | port: '8080', 9 | stats: { 10 | colors: true 11 | } 12 | }, 13 | webpackConfig.devServer 14 | ); 15 | const server = new WebpackDevServer(compiler, devServerOptions); 16 | 17 | server.listen(devServerOptions.port, '127.0.0.1', () => { 18 | console.log('srejs:Starting server on http://localhost:' + devServerOptions.port); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/index/about.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/index/home.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/vuex/app.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/player/index.less: -------------------------------------------------------------------------------- 1 | @import '../../common.less'; 2 | 3 | .playerContainer { 4 | position: relative; 5 | width: 100%; 6 | height: 2.1rem; 7 | .title { 8 | position: absolute; 9 | top: 10px; 10 | left: 10px; 11 | color: #fff; 12 | font-size: 15px; 13 | z-index: 100; 14 | } 15 | .ico { 16 | width: 45px; 17 | height: 45px; 18 | z-index: 100; 19 | position: absolute; 20 | left: 50%; 21 | top: 50%; 22 | transform: translate(-50%, -50%); 23 | width: 45px; 24 | height: 45px; 25 | z-index: 100; 26 | } 27 | .layer { 28 | position: absolute; 29 | width: 100%; 30 | height: 100%; 31 | z-index: 99; 32 | background-color: #000; 33 | opacity: 0.5; 34 | } 35 | } -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/vuex/app.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /packages/app/web/pages/list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 列表 15 | 16 | 17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /example/uma-css-module/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | // 此文件用于IED开发环境web目录下ts类型检测校验,不影响构建 2 | { 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "target": "ES2018", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "inlineSourceMap":true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "stripInternal": true, 14 | "pretty": true, 15 | "declaration": false, 16 | "strict": true, 17 | "noEmit": true, 18 | "baseUrl": "./", 19 | "strictNullChecks": true, 20 | "esModuleInterop": true, 21 | "jsx": "react", 22 | "paths": { 23 | "@/*": ["./*"] // 此处映射是相对于"baseUrl" 24 | } 25 | }, 26 | "include": [ 27 | "." 28 | ] 29 | } 30 | 31 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-float infinite 3s ease-in-out; 13 | } 14 | } 15 | 16 | .App-header { 17 | min-height: 100vh; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | } 24 | 25 | .App-link { 26 | color: rgb(112, 76, 182); 27 | } 28 | 29 | @keyframes App-logo-float { 30 | 0% { 31 | transform: translateY(0); 32 | } 33 | 50% { 34 | transform: translateY(10px); 35 | } 36 | 100% { 37 | transform: translateY(0px); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/app/web/pages/list/index.tsx: -------------------------------------------------------------------------------- 1 | import './index.scss'; 2 | import React from 'react'; 3 | type typeProps = { 4 | ListData: [string]; 5 | }; 6 | export default function (props: typeProps) { 7 | const { ListData } = props; 8 | return ( 9 |
10 |

List

11 |
    12 | {ListData.map((item, value) => { 13 | return ( 14 |
  • 15 | 16 | {item} 17 | 18 |
  • 19 | ); 20 | })} 21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | // 此文件用于IED开发环境web目录下ts类型检测校验,不影响构建 2 | { 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "target": "ES2018", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "inlineSourceMap":true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "stripInternal": true, 14 | "pretty": true, 15 | "declaration": false, 16 | "strict": true, 17 | "noEmit": true, 18 | "baseUrl": "./", 19 | "strictNullChecks": true, 20 | "esModuleInterop": true, 21 | "jsx": "react", 22 | "paths": { 23 | "@/*": ["./*"] // 此处映射是相对于"baseUrl" 24 | } 25 | }, 26 | "include": [ 27 | "." 28 | ] 29 | } 30 | 31 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/pages/detail/test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { RecommendDataNode, PlayerDataNode, BriefDataNode, Ddata } from '../../interface'; 3 | import Player from '../../components/player'; 4 | import Brief from '../../components/brief'; 5 | import Recommend from '../../components/recommend'; 6 | 7 | export default (props: Ddata) => ( 8 |
9 | { 10 | props?.detailData?.data[0].dataNode ?
11 | 12 | 13 | 14 |
:
暂无数据~~
15 | } 16 |
17 | ); 18 | -------------------------------------------------------------------------------- /packages/app/web/pages/ruleHistoryList/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{title}} 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import { createMemoryHistory, createWebHistory } from 'vue-router'; 2 | import App from './App.vue'; 3 | import About from './about.vue'; 4 | import Home from './home.vue'; 5 | 6 | // route-level code splitting 7 | // const About = () => import('./about.vue'); 8 | // const Home = () => import('./home.vue'); 9 | 10 | const isServer = typeof window === 'undefined'; 11 | 12 | const createHistory = isServer ? createMemoryHistory : createWebHistory; 13 | 14 | export default { 15 | App, 16 | Router: { 17 | history: createHistory('/index/'), 18 | routes: [ 19 | { path: '/about', props: true, component: About }, 20 | { path: '/home', props: true, component: Home }, 21 | { path: '/', redirect: '/home' } 22 | ] 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /packages/app-vue/web/pages/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseState02.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | let APP = () => { 3 | const [books, setBooks] = useState({ name: '语文', id: '1' }); 4 | return ( 5 |
6 |
7 | 索引: {books.id} 8 | 书名: {books.name} 9 |
10 | 11 | 20 |
21 | ); 22 | }; 23 | module.exports = APP; 24 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseState03.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | const books = [ 3 | { name: '语文', id: '1', state: '0' }, 4 | { name: '数学', id: '2', state: '1' }, 5 | { name: '英文', id: '3', state: '0' } 6 | ]; 7 | let APP = () => { 8 | const [book, setBooks] = useState(() => { 9 | let findBook = {}; 10 | books.map((_book, _index) => { 11 | if (_book.state == '1') { 12 | findBook = _book; 13 | } 14 | }); 15 | return findBook; 16 | }); 17 | return ( 18 |
19 |
20 | 索引: {book.id} 21 | 书名: {book.name} 22 | 状态: {book.name} 23 |
24 |
25 | ); 26 | }; 27 | module.exports = APP; 28 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/action/timeAction.js: -------------------------------------------------------------------------------- 1 | const GET_TIME = 'GET_TIME'; 2 | const RESET_TIME = 'RESET_TIME'; 3 | const ADD_TIME = 'ADD_TIME'; 4 | 5 | const getTime = time => { 6 | return { 7 | type: GET_TIME, 8 | time 9 | }; 10 | }; 11 | 12 | const resetTime = time => { 13 | return { 14 | type: RESET_TIME, 15 | time 16 | }; 17 | }; 18 | 19 | const addTime = () => { 20 | return { 21 | type: ADD_TIME 22 | }; 23 | }; 24 | 25 | const fetchTime = async () => { 26 | //异步处理 返回的是一个promise对象 通过then接收action 27 | let response = await fetch('http://localhost:9991/mock/count.json'); 28 | let listData = await response.json(); 29 | return getTime(listData.count); 30 | }; 31 | 32 | export { GET_TIME, RESET_TIME, ADD_TIME, getTime, resetTime, addTime, fetchTime }; 33 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /packages/app/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | // 此文件用于IED开发环境web目录下ts类型检测校验,不影响构建 2 | { 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "target": "ES2018", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "inlineSourceMap":true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "stripInternal": true, 14 | "pretty": true, 15 | "declaration": false, 16 | "strict": true, 17 | "noEmit": true, 18 | "baseUrl": "./", 19 | "strictNullChecks": true, 20 | "esModuleInterop": true, 21 | "jsx": "react", 22 | "paths": { 23 | "@/*": ["./*"] // 此处映射是相对于"baseUrl" 24 | }, 25 | "plugins": [{ "name": "typescript-plugin-css-modules" }] 26 | }, 27 | "include": [ 28 | "." 29 | ] 30 | } 31 | 32 | -------------------------------------------------------------------------------- /packages/app-vue3/web/pages/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/combine.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { merge } from 'webpack-merge'; 3 | import { webpackConfigPath } from '@srejs/common'; 4 | 5 | module.exports = function (config, isServer) { 6 | if (!fs.existsSync(webpackConfigPath)) { 7 | return config; 8 | } 9 | let customConfig = config; 10 | delete require.cache[require.resolve(webpackConfigPath)]; 11 | const configureWebpack = require(webpackConfigPath); 12 | if (typeof configureWebpack === 'function') { 13 | // apply customConfig 14 | customConfig = Reflect.apply(configureWebpack, config, [config, isServer ? 'ssr' : 'csr']); 15 | } 16 | 17 | if (typeof configureWebpack === 'object') { 18 | // webpack-merge 19 | customConfig = merge(config, configureWebpack); 20 | } 21 | 22 | return customConfig; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/combine.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { merge } from 'webpack-merge'; 3 | import { webpackConfigPath } from '@srejs/common'; 4 | 5 | module.exports = function (config, isServer) { 6 | if (!fs.existsSync(webpackConfigPath)) { 7 | return config; 8 | } 9 | let customConfig = config; 10 | delete require.cache[require.resolve(webpackConfigPath)]; 11 | const configureWebpack = require(webpackConfigPath); 12 | if (typeof configureWebpack === 'function') { 13 | // apply customConfig 14 | customConfig = Reflect.apply(configureWebpack, config, [config, isServer ? 'ssr' : 'csr']); 15 | } 16 | 17 | if (typeof configureWebpack === 'object') { 18 | // webpack-merge 19 | customConfig = merge(config, configureWebpack); 20 | } 21 | 22 | return customConfig; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/combine.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { merge } from 'webpack-merge'; 3 | import { webpackConfigPath } from '@srejs/common'; 4 | 5 | module.exports = function (config, isServer) { 6 | if (!fs.existsSync(webpackConfigPath)) { 7 | return config; 8 | } 9 | let customConfig = config; 10 | delete require.cache[require.resolve(webpackConfigPath)]; 11 | const configureWebpack = require(webpackConfigPath); 12 | if (typeof configureWebpack === 'function') { 13 | // apply customConfig 14 | customConfig = Reflect.apply(configureWebpack, config, [config, isServer ? 'ssr' : 'csr']); 15 | } 16 | 17 | if (typeof configureWebpack === 'object') { 18 | // webpack-merge 19 | customConfig = merge(config, configureWebpack); 20 | } 21 | 22 | return customConfig; 23 | }; 24 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/recommend/index.less: -------------------------------------------------------------------------------- 1 | .title { 2 | display: flex; 3 | height: 50px; 4 | align-items: center; 5 | font-size: 16px; 6 | color: #000; 7 | margin-left: 0.09rem; 8 | font-weight: 700; 9 | } 10 | .reContainer { 11 | display: flex; 12 | flex-wrap: wrap; 13 | justify-content: space-between; 14 | margin: 0 auto; 15 | width: 3.5rem; 16 | } 17 | .reContent { 18 | display: flex; 19 | width: 33%; 20 | flex-direction: column; 21 | white-space: nowrap; 22 | text-overflow: ellipsis; 23 | // padding-right: 0.03rem; 24 | img { 25 | width: 100%; 26 | height: 1.72rem; 27 | } 28 | .vTitle { 29 | color: #444; 30 | font-size: 15px; 31 | font-weight: 400; 32 | } 33 | .subTitle { 34 | font-size: 13px; 35 | color: #999; 36 | white-space: nowrap; 37 | text-overflow: ellipsis; 38 | overflow-x: hidden; 39 | } 40 | } -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseEffect04.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | let APP = () => { 3 | let initState = async () => { 4 | let response = await fetch('http://localhost:9991/mock/count.json'); 5 | let listData = await response.json(); 6 | return listData.count; 7 | }; 8 | 9 | const [count, setCount] = useState(0); 10 | useEffect(() => { 11 | initState().then(defaultCount => { 12 | setCount(defaultCount); 13 | console.log(`useEffect异步获取count${defaultCount}`); 14 | }); 15 | console.log(`useEffect初始渲染`); 16 | }, []); 17 | return ( 18 |
19 |
20 | Count:{count} 21 |
22 | 23 |
24 | ); 25 | }; 26 | module.exports = APP; 27 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/rectangle/index.less: -------------------------------------------------------------------------------- 1 | @import '../../common.less'; 2 | 3 | .pbbContainer { 4 | display: flex; 5 | flex-flow: row wrap; 6 | justify-content: space-between; 7 | overflow: hidden; 8 | box-sizing: border-box; 9 | 10 | .pbbItemContainer{ 11 | position: relative; 12 | display: block; 13 | width: 50%; 14 | padding-right: 2px; 15 | box-sizing: border-box; 16 | overflow: hidden; 17 | &:nth-child(2n) { 18 | margin-right: -3px; 19 | } 20 | } 21 | 22 | .defaultItemBg { 23 | position: relative; 24 | width: 100%; 25 | height: 1.04rem; 26 | background-repeat: no-repeat; 27 | background-position: '0 0'; 28 | background-size: 'cover'; 29 | } 30 | 31 | } 32 | .pbbDescContainer { 33 | width: 100%; 34 | display: flex; 35 | flex-direction: column; 36 | } 37 | .pbbImg { 38 | width: 100%; 39 | height: 1.04rem; 40 | } 41 | .pbbName { 42 | width: 1.7rem; 43 | } -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseEffect03.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | let APP = () => { 3 | const [time, setTime] = useState(new Date().getTime()); 4 | const [flag, setFlag] = useState(true); 5 | useEffect(() => { 6 | let timer = setTimeout(function() { 7 | setTime(new Date().getTime()); 8 | }, 0); 9 | console.log('effect has be run!'); 10 | return function() { 11 | clearTimeout(timer); 12 | }; 13 | }, [flag]); //只有flag参数变化后才会重现执行effect 14 | return ( 15 |
16 |
17 | 当前时间: {time} 18 | 24 |
25 |
26 | ); 27 | }; 28 | module.exports = APP; 29 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/hooks/useContextHooks.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import { useReducer } from 'react'; 3 | import { ActionType } from '../interface'; 4 | 5 | export default (props:any) => { 6 | function reducer(state: any, action: ActionType) { 7 | // 将触发reducer后更新的状态存储到本地已达到多个页面数据共享 8 | window.sessionStorage.setItem('payload', JSON.stringify(action.payload)); 9 | switch (action.type) { 10 | case 'updateContext': 11 | 12 | return { ...state, ...action.payload }; 13 | default: 14 | throw new Error(`Action type ${action.type} is incorrect Please use type updateContext `); 15 | } 16 | } 17 | 18 | // 解决页面组件跳转或者刷新页面时更新的状态共享 19 | const payLoad = typeof window !== 'undefined' && JSON.parse(window.sessionStorage.getItem('payload') || '{}'); 20 | 21 | return useReducer(reducer, { ...props, ...payLoad }); 22 | }; 23 | -------------------------------------------------------------------------------- /doc/vue/vue-router.md: -------------------------------------------------------------------------------- 1 | # 使用vue-router 2 | 3 | > 当vue页面组件需要和vue-router结合开发单页面应用时,在入口文件中我们也可以通过Router属性导出路由配置。 4 | 5 | - 客户端页面组件入口文件路由配置 6 | 7 | ```js 8 | import App from './App.vue'; 9 | import About from './about.vue'; 10 | import Home from './home.vue'; 11 | 12 | export default { 13 | App, 14 | Router: { 15 | mode: 'history', 16 | fallback: false, 17 | base: '/index/', 18 | scrollBehavior: () => ({ y: 0 }), 19 | routes: [ 20 | { path: '/about', props: true, component: About }, 21 | { path: '/home', props: true, component: Home }, 22 | { path: '/', redirect: '/home' } 23 | ] 24 | } 25 | }; 26 | ``` 27 | 28 | **注意:服务端渲染模式下不支持使用import动态导入组件方式进行路由懒加载** 29 | 30 | - 服务端路由 31 | 32 | > 对于服务端我们需要保持客户端和服务端路由一致,否则会出现子路由页面刷新`404`现象。 33 | 34 | - 页面路由获取数据 35 | 36 | > 在页面组件中页面数据获取方式和普通页面组件保持一致,我们可以使用服务端渲染props直出和asyncData钩子函数两种方式获取,具体使用参考[数据获取](./initState.md) 37 | -------------------------------------------------------------------------------- /doc/vue3/vue-router.md: -------------------------------------------------------------------------------- 1 | # 使用vue-router 2 | 3 | > 当vue页面组件需要和vue-router结合开发单页面应用时,在入口文件中我们也可以通过Router属性导出路由配置。 4 | 5 | - 客户端页面组件入口文件路由配置 6 | 7 | ```js 8 | import App from './App.vue'; 9 | import About from './about.vue'; 10 | import Home from './home.vue'; 11 | 12 | const isServer = typeof window === 'undefined'; 13 | 14 | const createHistory = isServer ? createMemoryHistory : createWebHistory; 15 | 16 | export default { 17 | App, 18 | Router: { 19 | history: createHistory('/index/'), 20 | routes: [ 21 | { path: '/about', props: true, component: About }, 22 | { path: '/home', props: true, component: Home }, 23 | { path: '/', redirect: '/home' } 24 | ] 25 | } 26 | }; 27 | ``` 28 | 29 | - 服务端路由 30 | 31 | > 对于服务端我们需要保持客户端和服务端路由一致,否则会出现子路由页面刷新`404`现象。 32 | 33 | - 页面路由获取数据 34 | 35 | > 在页面组件中页面数据获取方式和普通页面组件保持一致,我们可以使用服务端渲染props直出和asyncData钩子函数两种方式获取,具体使用参考[数据获取](./initState.md) 36 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/search/index.module.less: -------------------------------------------------------------------------------- 1 | .searchContainer { 2 | width: 100%; 3 | height: 50px; 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | &:after{ 8 | content: ''; 9 | width: 25px; 10 | margin-left: -30px; 11 | background-image: url(https://img.alicdn.com/tfs/TB15zSoX21TBuNjy0FjXXajyXXa-48-48.png); 12 | height: 30px; 13 | background-size: contain; 14 | background-repeat: no-repeat; 15 | line-height: 30px; 16 | } 17 | } 18 | .input{ 19 | width: 80%; 20 | height: 30px; 21 | border: 0 solid transparent; 22 | border-radius: 100px; 23 | font-family: Microsoft YaHei,SimHei,helvetica,arial,verdana,tahoma,sans-serif; 24 | font-size: 14px; 25 | background: rgba(0,0,0,.06); 26 | text-indent: 15px; 27 | outline: none; 28 | margin: 20px 0px; 29 | } 30 | .searchImg { 31 | width: 25px; 32 | height: 30px; 33 | margin-left: -30px; 34 | display: inline-block; 35 | z-index: 1; 36 | } -------------------------------------------------------------------------------- /packages/app/web/pages/redux/reducer/timeReducer.js: -------------------------------------------------------------------------------- 1 | import { GET_TIME, RESET_TIME, ADD_TIME } from './../action/timeAction'; 2 | 3 | const timeReducer = (state, action) => { 4 | // state当前状态 action下面的是参数可转换到state中去更新 5 | let handleGetTime = () => { 6 | return Object.assign({}, state, { 7 | time: action.time 8 | }); 9 | }; 10 | 11 | let handleResetTime = () => { 12 | return Object.assign({}, state, { 13 | time: action.time 14 | }); 15 | }; 16 | 17 | let handleAddTime = () => { 18 | return Object.assign({}, state, { 19 | time: state.time + 1 20 | }); 21 | }; 22 | switch (action.type) { 23 | case GET_TIME: 24 | return handleGetTime(); 25 | case RESET_TIME: 26 | return handleResetTime(); 27 | case ADD_TIME: 28 | return handleAddTime(); 29 | default: 30 | return state; 31 | } 32 | }; 33 | 34 | module.exports = timeReducer; 35 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/server.js: -------------------------------------------------------------------------------- 1 | import nodeExternals from 'webpack-node-externals'; 2 | import common, { serverDir, cwd } from '@srejs/common'; 3 | import { getBaseconfig } from './base'; 4 | import combine from './combine'; 5 | 6 | export function getServerconfig(page) { 7 | let baseConfig = getBaseconfig(page, true); 8 | let additionalModuleDirs = [cwd + '/node_modules']; 9 | if (common.isDev()) { 10 | additionalModuleDirs.push(cwd); 11 | } 12 | let config = { 13 | ...baseConfig, 14 | watch: true, 15 | target: 'node', 16 | output: { 17 | publicPath: '/', 18 | libraryTarget: 'umd', 19 | globalObject: 'this', //webpack4之后如果umd构建在浏览器和node环境中均可使用需要设置成this 20 | filename: '[name].js', //打包后输出文件的文件名 21 | path: serverDir //打包后的文件存放的地方 22 | }, 23 | externals: [nodeExternals({ allowlist: [/\.(css|vue)$/], additionalModuleDirs })] 24 | }; 25 | return combine(config, true); 26 | } 27 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/server.js: -------------------------------------------------------------------------------- 1 | import nodeExternals from 'webpack-node-externals'; 2 | import common, { serverDir, cwd } from '@srejs/common'; 3 | import { getBaseconfig } from './base'; 4 | import combine from './combine'; 5 | 6 | export function getServerconfig(page) { 7 | let baseConfig = getBaseconfig(page, true); 8 | let additionalModuleDirs = [cwd + '/node_modules']; 9 | if (common.isDev()) { 10 | additionalModuleDirs.push(cwd); 11 | } 12 | let config = { 13 | ...baseConfig, 14 | watch: true, 15 | target: 'node', 16 | output: { 17 | publicPath: '/', 18 | libraryTarget: 'umd', 19 | globalObject: 'this', //webpack4之后如果umd构建在浏览器和node环境中均可使用需要设置成this 20 | filename: '[name].js', //打包后输出文件的文件名 21 | path: serverDir //打包后的文件存放的地方 22 | }, 23 | externals: [nodeExternals({ allowlist: [/\.(css|vue)$/], additionalModuleDirs })] 24 | }; 25 | return combine(config, true); 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /example/uma-css-module/src/controller/index.controller.ts: -------------------------------------------------------------------------------- 1 | import { BaseController, Path } from '@umajs/core'; 2 | import { Result } from '@umajs/plugin-react-ssr'; 3 | 4 | @Path('/') 5 | export default class Index extends BaseController { 6 | @Path() 7 | @Path('/less') 8 | index() { 9 | return Result.reactView( 10 | 'less', 11 | { des: '使用前请查看官方对于css模块化的介绍。https://github.com/css-modules/css-modules' }, 12 | { cache: false }, 13 | ); 14 | } 15 | 16 | @Path('/css') 17 | css() { 18 | return Result.reactView( 19 | 'css', 20 | { des: '使用前请查看官方对于css模块化的介绍。https://github.com/css-modules/css-modules' }, 21 | { cache: false }, 22 | ); 23 | } 24 | 25 | @Path('/scss') 26 | scss() { 27 | return Result.reactView( 28 | 'scss', 29 | { des: '使用前请查看官方对于css模块化的介绍。https://github.com/css-modules/css-modules' }, 30 | { cache: false }, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/features/counter/counterSlice.spec.js: -------------------------------------------------------------------------------- 1 | import counterReducer, { 2 | increment, 3 | decrement, 4 | incrementByAmount, 5 | } from './counterSlice'; 6 | 7 | describe('counter reducer', () => { 8 | const initialState = { 9 | value: 3, 10 | status: 'idle', 11 | }; 12 | it('should handle initial state', () => { 13 | expect(counterReducer(undefined, { type: 'unknown' })).toEqual({ 14 | value: 0, 15 | status: 'idle', 16 | }); 17 | }); 18 | 19 | it('should handle increment', () => { 20 | const actual = counterReducer(initialState, increment()); 21 | expect(actual.value).toEqual(4); 22 | }); 23 | 24 | it('should handle decrement', () => { 25 | const actual = counterReducer(initialState, decrement()); 26 | expect(actual.value).toEqual(2); 27 | }); 28 | 29 | it('should handle incrementByAmount', () => { 30 | const actual = counterReducer(initialState, incrementByAmount(2)); 31 | expect(actual.value).toEqual(5); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/server.js: -------------------------------------------------------------------------------- 1 | import nodeExternals from 'webpack-node-externals'; 2 | import common, { serverDir, cwd } from '@srejs/common'; 3 | import { getBaseconfig } from './base'; 4 | import combine from './combine'; 5 | 6 | export function getServerconfig(page) { 7 | let baseConfig = getBaseconfig(page, true); 8 | let additionalModuleDirs = [cwd + '/node_modules']; 9 | if (common.isDev()) { 10 | additionalModuleDirs.push(cwd); 11 | } 12 | let config = { 13 | ...baseConfig, 14 | watch: true, 15 | target: 'node', 16 | output: { 17 | publicPath: '/', 18 | libraryTarget: 'umd', 19 | globalObject: 'this', //webpack4之后如果umd构建在浏览器和node环境中均可使用需要设置成this 20 | filename: '[name].js', //打包后输出文件的文件名 21 | path: serverDir //打包后的文件存放的地方 22 | }, 23 | externals: [ 24 | nodeExternals({ allowlist: [/\.(?!(?:jsx?|json)$).{1,5}$/i], additionalModuleDirs }) 25 | ] 26 | }; 27 | return combine(config, true); 28 | } 29 | -------------------------------------------------------------------------------- /packages/react/src/send-html.js: -------------------------------------------------------------------------------- 1 | import generateETag from 'etag'; 2 | import fresh from 'fresh'; 3 | 4 | export function sendHTML(ctx, html, { generateEtags }) { 5 | let { req, res } = ctx; 6 | function isResSent(res) { 7 | return res.finished || res.headersSent; 8 | } 9 | 10 | if (isResSent(res)) return; 11 | if (typeof html == 'object') { 12 | res.statusCode = 200; 13 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 14 | ctx.body = html; 15 | } else { 16 | const etag = generateEtags ? generateETag(html) : undefined; 17 | 18 | if (fresh(req.headers, { etag })) { 19 | res.statusCode = 304; 20 | res.end(); 21 | return; 22 | } 23 | 24 | if (etag) { 25 | res.setHeader('ETag', etag); 26 | } 27 | res.statusCode = 200; 28 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 29 | res.setHeader('Content-Length', Buffer.byteLength(html)); 30 | res.end(req.method === 'HEAD' ? null : html); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/vue/src/send-html.js: -------------------------------------------------------------------------------- 1 | import generateETag from 'etag'; 2 | import fresh from 'fresh'; 3 | 4 | export function sendHTML(ctx, html, { generateEtags }) { 5 | let { req, res } = ctx; 6 | function isResSent(res) { 7 | return res.finished || res.headersSent; 8 | } 9 | 10 | if (isResSent(res)) return; 11 | if (typeof html == 'object') { 12 | res.statusCode = 200; 13 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 14 | ctx.body = html; 15 | } else { 16 | const etag = generateEtags ? generateETag(html) : undefined; 17 | 18 | if (fresh(req.headers, { etag })) { 19 | res.statusCode = 304; 20 | res.end(); 21 | return; 22 | } 23 | 24 | if (etag) { 25 | res.setHeader('ETag', etag); 26 | } 27 | res.statusCode = 200; 28 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 29 | res.setHeader('Content-Length', Buffer.byteLength(html)); 30 | res.end(req.method === 'HEAD' ? null : html); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/vue3/src/send-html.js: -------------------------------------------------------------------------------- 1 | import generateETag from 'etag'; 2 | import fresh from 'fresh'; 3 | 4 | export function sendHTML(ctx, html, { generateEtags }) { 5 | let { req, res } = ctx; 6 | function isResSent(res) { 7 | return res.finished || res.headersSent; 8 | } 9 | 10 | if (isResSent(res)) return; 11 | if (typeof html == 'object') { 12 | res.statusCode = 200; 13 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 14 | ctx.body = html; 15 | } else { 16 | const etag = generateEtags ? generateETag(html) : undefined; 17 | 18 | if (fresh(req.headers, { etag })) { 19 | res.statusCode = 304; 20 | res.end(); 21 | return; 22 | } 23 | 24 | if (etag) { 25 | res.setHeader('ETag', etag); 26 | } 27 | res.statusCode = 200; 28 | res.setHeader('Content-Type', 'text/html; charset=utf-8'); 29 | res.setHeader('Content-Length', Buffer.byteLength(html)); 30 | res.end(req.method === 'HEAD' ? null : html); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/brief/index.less: -------------------------------------------------------------------------------- 1 | .brief-info { 2 | padding: 18px 0 0px; 3 | position: relative; 4 | overflow: hidden; 5 | } 6 | 7 | .brief-title { 8 | display: flex; 9 | justify-content: flex-start; 10 | align-items: center; 11 | margin-bottom: 8px; 12 | padding-left: 10px; 13 | span{ 14 | font-size: 11px; 15 | text-align: center; 16 | color: #fff; 17 | font-weight: bold; 18 | background: #FC4273; 19 | padding: 1px 4px; 20 | margin-right: 9px; 21 | border-radius: 3px; 22 | &.icon-GOLDEN{ 23 | background: #EBBA73; 24 | } 25 | } 26 | h1{ 27 | color: #333; 28 | font-size: 18px; 29 | margin-bottom: 0; 30 | } 31 | } 32 | 33 | .brief-score{ 34 | font-size: 12px;; 35 | padding-left: 10px; 36 | color: #666; 37 | .hotVv{ 38 | img{ 39 | width: 14px; 40 | vertical-align: middle; 41 | margin-top: -2px 42 | } 43 | } 44 | 45 | .divide{ 46 | transform: scale(0.6); 47 | margin: 0 5px; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /packages/app/web/pages/redux/redux.scss: -------------------------------------------------------------------------------- 1 | //sass style 2 | //------------------------------- 3 | @use "sass:math"; 4 | 5 | $baseFontSize: 32px !default; 6 | 7 | 8 | // pixels to rems 9 | @function pxToRem($px) { 10 | @return math.div($px, $baseFontSize) * 1rem; 11 | } 12 | html,body,#app{ 13 | font-size: 16px; 14 | width: 100%; 15 | height: 100%; 16 | overflow-y: auto; 17 | } 18 | .demo{ 19 | width: 100%; 20 | height: 100%; 21 | margin: 0 auto; /*水平居中*/ 22 | position: relative; 23 | top: 50%; /*偏移*/ 24 | transform: translateY(-50%); 25 | background-image: url('images/srejs.png'); 26 | background-size: auto; 27 | background-position-y: pxToRem(70px); 28 | font-weight: bold; 29 | font-size: $baseFontSize; 30 | text-align: center; 31 | color: #ffffff; 32 | li a{ 33 | color:#03a9f4; 34 | } 35 | .title,.footer{ 36 | color: white; 37 | font-size: pxToRem(24px); 38 | } 39 | .footer{ 40 | text-align: center; 41 | a{ 42 | color: #ffffff !important; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 dazjean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/pages/index/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Slider from '../../components/slider'; 3 | import Rectangle from '../../components/rectangle'; 4 | import Search from '../../components/search'; 5 | import Context from '../../context'; 6 | import { IData } from '../../interface'; 7 | import useContextHooks from '../../hooks/useContextHooks'; 8 | 9 | export default (props: IData) => { 10 | const [state, dispatch] = useContextHooks(props); 11 | 12 | return ( 13 | 14 |
15 | 16 | { 17 | state?.indexData?.data?.[0]?.components ?
18 | 19 | 20 |
: 21 | } 22 |
23 |
24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseEffect02.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | let APP = () => { 3 | const [time, setTime] = useState(new Date().getTime()); 4 | useEffect(() => { 5 | console.log('初始渲染!'); 6 | return function() { 7 | // clearTimeout(timer); 8 | console.log('被卸载了!'); 9 | }; 10 | }); 11 | return ( 12 |
13 |
14 | 当前时间: {time} 15 | 21 |
22 |
23 | ); 24 | }; 25 | let Parent = () => { 26 | const [flag, setFlag] = useState(true); 27 | return ( 28 |
29 | {flag && } 30 | 36 |
37 | ); 38 | }; 39 | module.exports = Parent; 40 | -------------------------------------------------------------------------------- /packages/react/src/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as Koa from 'koa'; 3 | 4 | type TssrOptions = { 5 | ssr: boolean; 6 | cache?: boolean; 7 | }; 8 | 9 | type TcoreOptions = { 10 | ssr?: boolean; // 开启服务端渲染 11 | cache?: boolean; // 开启缓存 12 | rootDir?: string; // 工程根文件夹目录名称 13 | rootNode?: string; // 客户端渲染挂载根元素ID 14 | prefixCDN?: string, // 构建后静态资源CDN地址前缀 15 | prefixRouter?: string, // 默认页面路由前缀(在defaultRouter设置为true时有效) 16 | log?:boolean // 开发环境日志输出 17 | }; 18 | 19 | declare class Srejs { 20 | /** 21 | * 22 | * @param app koa实例 23 | * @param dev 默认true,将改写process.env.NODE_ENV为development 24 | * @param defaultRouter 使用默认路由 默认false 25 | * @param options 框架配置属性 26 | */ 27 | constructor(app: Koa, dev?: boolean, defaultRouter?: boolean, options?: TcoreOptions); 28 | /** 29 | * 30 | * @param ctx 31 | * @param viewName 页面组件名称 32 | * @param initProps 初始化props 33 | * @param options 局部属性 34 | */ 35 | render(ctx: Koa.Context, viewName: string, initProps?: object, options?: TssrOptions): Promise; 36 | } 37 | 38 | export default Srejs; 39 | -------------------------------------------------------------------------------- /packages/vue/src/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as Koa from 'koa'; 3 | 4 | type TssrOptions = { 5 | ssr: boolean; 6 | cache?: boolean; 7 | }; 8 | 9 | type TcoreOptions = { 10 | ssr?: boolean; // 开启服务端渲染 11 | cache?: boolean; // 开启缓存 12 | rootDir?: string; // 工程根文件夹目录名称 13 | rootNode?: string; // 客户端渲染挂载根元素ID 14 | prefixCDN?: string, // 构建后静态资源CDN地址前缀 15 | prefixRouter?: string, // 默认页面路由前缀(在defaultRouter设置为true时有效) 16 | log?:boolean // 开发环境日志输出 17 | }; 18 | 19 | declare class Srejs { 20 | /** 21 | * 22 | * @param app koa实例 23 | * @param dev 默认true,将改写process.env.NODE_ENV为development 24 | * @param defaultRouter 使用默认路由 默认false 25 | * @param options 框架配置属性 26 | */ 27 | constructor(app: Koa, dev?: boolean, defaultRouter?: boolean, options?: TcoreOptions); 28 | /** 29 | * 30 | * @param ctx 31 | * @param viewName 页面组件名称 32 | * @param initProps 初始化props 33 | * @param options 局部属性 34 | */ 35 | render(ctx: Koa.Context, viewName: string, initProps?: object, options?: TssrOptions): Promise; 36 | } 37 | 38 | export default Srejs; 39 | -------------------------------------------------------------------------------- /packages/vue3/src/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as Koa from 'koa'; 3 | 4 | type TssrOptions = { 5 | ssr: boolean; 6 | cache?: boolean; 7 | }; 8 | 9 | type TcoreOptions = { 10 | ssr?: boolean; // 开启服务端渲染 11 | cache?: boolean; // 开启缓存 12 | rootDir?: string; // 工程根文件夹目录名称 13 | rootNode?: string; // 客户端渲染挂载根元素ID 14 | prefixCDN?: string, // 构建后静态资源CDN地址前缀 15 | prefixRouter?: string, // 默认页面路由前缀(在defaultRouter设置为true时有效) 16 | log?:boolean // 开发环境日志输出 17 | }; 18 | 19 | declare class Srejs { 20 | /** 21 | * 22 | * @param app koa实例 23 | * @param dev 默认true,将改写process.env.NODE_ENV为development 24 | * @param defaultRouter 使用默认路由 默认false 25 | * @param options 框架配置属性 26 | */ 27 | constructor(app: Koa, dev?: boolean, defaultRouter?: boolean, options?: TcoreOptions); 28 | /** 29 | * 30 | * @param ctx 31 | * @param viewName 页面组件名称 32 | * @param initProps 初始化props 33 | * @param options 局部属性 34 | */ 35 | render(ctx: Koa.Context, viewName: string, initProps?: object, options?: TssrOptions): Promise; 36 | } 37 | 38 | export default Srejs; 39 | -------------------------------------------------------------------------------- /doc/react/htmlTemplate.md: -------------------------------------------------------------------------------- 1 | # 自定义html 2 | > 框架内置`HTMLWebpackPlugin`插件,开发者在页面组件同级目录下可以覆盖默认html模板自定义引入第三方资源和脚本。 3 | 4 | ```html 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | srejs 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | ``` 27 | 28 | ## 自定义模板文件命名规则 29 | 为满足业务引入第三方脚本也提供了以下方式自定义html模板。 30 | - `web/pages/xxx/index.html`(局部页面生效) 31 | - `web/index.html`(全局生效) 32 | 33 | **优先级**`web/pages/xxx/index.html` > `web/index.html` -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseReducer.js: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from 'react'; 2 | import TimeReducer from './../reducer/timeReducer'; 3 | import { resetTime, addTime, fetchTime } from './../action/timeAction'; 4 | function Clock() { 5 | const [reduxState, dispatch] = useReducer(TimeReducer, { time: 100000 }); 6 | return ( 7 |
8 | Seco24ndsdfdsfdsf: {reduxState.time} 9 | 18 | 24 | 30 |
31 | ); 32 | } 33 | module.exports = Clock; 34 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/recommend/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { RecommendDataNode } from '../../interface'; 3 | import './index.less'; 4 | 5 | interface Props { 6 | data: RecommendDataNode[] 7 | } 8 | 9 | function Recommend(props: Props) { 10 | const { data } = props; 11 | 12 | return ( 13 |
14 |
15 | 为你推荐 16 |
17 |
18 | 19 | { 20 | data.map((item) => ( 21 |
22 | 23 |
24 | {item.data.title} 25 |
26 |
27 | {item.data.subtitle} 28 |
29 |
30 | )) 31 | } 32 |
33 |
34 | ); 35 | } 36 | 37 | export default Recommend; 38 | -------------------------------------------------------------------------------- /packages/app/web/pages/redux/page/UseContext.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext } from 'react'; 2 | const themes = { 3 | light: { 4 | color: '#000000', 5 | background: '#eeeeee' 6 | }, 7 | dark: { 8 | color: '#ffffff', 9 | background: '#222222' 10 | } 11 | }; 12 | 13 | const ThemeContext = React.createContext( 14 | themes.dark // default value 15 | ); 16 | let APP = () => { 17 | const [time, setTime] = useState(new Date().getTime()); 18 | const context = useContext(ThemeContext); 19 | console.log(context); 20 | return ( 21 |
22 | 当前时间: {time} 23 |
24 | ); 25 | }; 26 | let Parent = () => { 27 | const [flag, setFlag] = useState(true); 28 | return ( 29 | 30 |
31 | 32 | 38 |
39 |
40 | ); 41 | }; 42 | module.exports = Parent; 43 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/player/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { PlayerDataNode } from '../../interface'; 3 | import './index.less'; 4 | 5 | interface Props { 6 | data: PlayerDataNode[] 7 | } 8 | function Player(props: Props) { 9 | const [play, setPlay] = useState(false); 10 | const { data } = props.data[0]; 11 | 12 | return ( 13 |
14 | { 15 | play ?
16 | 19 |
:
22 |
{data.title}
23 | {/* setPlay(true)} /> */} 24 |
25 |
26 | } 27 |
28 | ); 29 | } 30 | 31 | export default Player; 32 | -------------------------------------------------------------------------------- /packages/app/web/pages/list/index.scss: -------------------------------------------------------------------------------- 1 | //sass style 2 | //------------------------------- 3 | @use "sass:math"; 4 | 5 | $baseFontSize: 32px !default; 6 | 7 | 8 | // pixels to rems 9 | @function pxToRem($px) { 10 | @return math.div($px, $baseFontSize) * 1rem; 11 | } 12 | body, 13 | div, 14 | dl, 15 | dt, 16 | dd, 17 | ul, 18 | ol, 19 | li, 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | h5, 25 | h6, 26 | pre, 27 | form, 28 | fieldset, 29 | input, 30 | textarea, 31 | p, 32 | blockquote, 33 | th, 34 | td, 35 | header, 36 | img 37 | { 38 | margin: 0; 39 | padding: 0; 40 | font-family: '微软雅黑'; 41 | } 42 | html,body,#app{ 43 | height: 100%; 44 | width: 100%; 45 | font-size: 16px; 46 | overflow-y: auto; 47 | } 48 | 49 | .list{ 50 | width: 100%; 51 | height: 100%; 52 | margin: 0 auto; /*水平居中*/ 53 | position: relative; 54 | top: 50%; /*偏移*/ 55 | transform: translateY(-50%); 56 | background-size: auto; 57 | background-position-y: pxToRem(70px); 58 | font-weight: bold; 59 | font-size: $baseFontSize; 60 | li{ 61 | background-color: #f9f1f1; 62 | border: #bdbbbb 1px solid; 63 | margin: 5px; 64 | } 65 | .item{ 66 | color:#03a9f4; 67 | } 68 | } -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/interface/detail-index.ts: -------------------------------------------------------------------------------- 1 | export interface Ddata { 2 | detailData?: { 3 | data: Data[] 4 | } 5 | } 6 | export interface Data { 7 | dataNode: RecommendDataNode[] | PlayerDataNode[] | BriefDataNode[] 8 | } 9 | 10 | export interface PlayerDataNode { 11 | data: { 12 | img: string 13 | title: string 14 | } 15 | } 16 | 17 | export interface RecommendDataNode { 18 | data: { 19 | heat: string 20 | summary: string 21 | img: string 22 | titleLine: number 23 | summaryType: string 24 | title: string 25 | subtitleType: string 26 | subtitle: string 27 | } 28 | } 29 | 30 | export interface BriefDataNode { 31 | data: { 32 | showName: string 33 | heat: string 34 | heatIcon: string 35 | updateInfo: string 36 | mark: { 37 | type: string 38 | mediaMarkType: string 39 | mediaMarkEnum: { 40 | name: string 41 | } 42 | data: { 43 | text: string 44 | color: string 45 | colorValue?: string 46 | img?: string 47 | } 48 | } 49 | showImg: boolean 50 | subTitleList: subTitle[] 51 | } 52 | } 53 | 54 | export interface subTitle { 55 | subtitle: string 56 | subtitleType: string 57 | } 58 | -------------------------------------------------------------------------------- /packages/vue/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "prettier" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "prettier/prettier":["error",{ 36 | "printWidth": 100, 37 | "tabWidth": 4, 38 | "semi": true, 39 | "trailingComma": "none", 40 | "singleQuote": true, 41 | "bracketSpacing": true, 42 | "jsxBracketSameLine": true 43 | }] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/pages/detail/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { RecommendDataNode, PlayerDataNode, BriefDataNode, Ddata } from '../../interface'; 3 | import Player from '../../components/player'; 4 | import Brief from '../../components/brief'; 5 | import Recommend from '../../components/recommend'; 6 | import Search from '../../components/search'; 7 | import Context from '../../context'; 8 | import useContextHooks from '../../hooks/useContextHooks'; 9 | 10 | export default (props: Ddata) => { 11 | const [state, dispatch] = useContextHooks(props); 12 | 13 | return ( 14 | 15 |
16 | 17 | { 18 | props?.detailData?.data[0].dataNode ?
19 | 20 | 21 | 22 |
:
暂无数据~~
23 | } 24 |
25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/app-vue/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "prettier" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "prettier/prettier":["error",{ 36 | "printWidth": 100, 37 | "tabWidth": 4, 38 | "semi": true, 39 | "trailingComma": "none", 40 | "singleQuote": true, 41 | "bracketSpacing": true, 42 | "jsxBracketSameLine": true 43 | }] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/app-vue3/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "prettier" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "prettier/prettier":["error",{ 36 | "printWidth": 100, 37 | "tabWidth": 4, 38 | "semi": true, 39 | "trailingComma": "none", 40 | "singleQuote": true, 41 | "bracketSpacing": true, 42 | "jsxBracketSameLine": true 43 | }] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/vue3/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "prettier" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "prettier/prettier":["error",{ 36 | "printWidth": 100, 37 | "tabWidth": 4, 38 | "semi": true, 39 | "trailingComma": "none", 40 | "singleQuote": true, 41 | "bracketSpacing": true, 42 | "jsxBracketSameLine": true 43 | }] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/react/bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var commander = require('commander'); 3 | commander 4 | .version('1.0.0') 5 | .option('-d, --dev [page]', '启动客户端渲染开发模式') 6 | .option('-b, --build [page]', '生成环境构建编译,输出目录默认dist/') 7 | .option('-a, --analyzer [page]', '编译构建打包分析'); 8 | 9 | const build = (page) => { 10 | const { build } = require('../lib/build'); 11 | if (page == 'true') { 12 | process.env.NODE_ENV = 'production'; 13 | page = JSON.parse(page); 14 | } else if (page == 'false') { 15 | process.env.NODE_ENV = 'development'; 16 | page = JSON.parse(page); 17 | } else { 18 | process.env.NODE_ENV = 'production'; 19 | } 20 | build(page); 21 | }; 22 | 23 | // webpack build bundle 24 | commander.command('build [page]').action((page = true) => { 25 | build(page); 26 | }); 27 | 28 | // Analyzer webpack build bundle 29 | commander.command('analyzer [page]').action((page = true) => { 30 | process.argv.push('--analyzer'); 31 | build(page); 32 | }); 33 | 34 | // start with webpack-dev-server with csr 35 | commander.command('dev [page]').action((page = true) => { 36 | const { dev } = require('../lib/dev'); 37 | process.env.NODE_ENV = 'development'; 38 | dev(page); 39 | }); 40 | 41 | commander.parse(process.argv); 42 | -------------------------------------------------------------------------------- /packages/vue/bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var commander = require('commander'); 3 | commander 4 | .version('1.0.0') 5 | .option('-d, --dev [page]', '启动客户端渲染开发模式') 6 | .option('-b, --build [page]', '生成环境构建编译,输出目录默认dist/') 7 | .option('-a, --analyzer [page]', '编译构建打包分析'); 8 | 9 | const build = (page) => { 10 | const { build } = require('../lib/build'); 11 | if (page == 'true') { 12 | process.env.NODE_ENV = 'production'; 13 | page = JSON.parse(page); 14 | } else if (page == 'false') { 15 | process.env.NODE_ENV = 'development'; 16 | page = JSON.parse(page); 17 | } else { 18 | process.env.NODE_ENV = 'production'; 19 | } 20 | build(page); 21 | }; 22 | 23 | // webpack build bundle 24 | commander.command('build [page]').action((page = true) => { 25 | build(page); 26 | }); 27 | 28 | // Analyzer webpack build bundle 29 | commander.command('analyzer [page]').action((page = true) => { 30 | process.argv.push('--analyzer'); 31 | build(page); 32 | }); 33 | 34 | // start with webpack-dev-server with csr 35 | commander.command('dev [page]').action((page = true) => { 36 | const { dev } = require('../lib/dev'); 37 | process.env.NODE_ENV = 'development'; 38 | dev(page); 39 | }); 40 | 41 | commander.parse(process.argv); 42 | -------------------------------------------------------------------------------- /packages/vue3/bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var commander = require('commander'); 3 | commander 4 | .version('1.0.0') 5 | .option('-d, --dev [page]', '启动客户端渲染开发模式') 6 | .option('-b, --build [page]', '生成环境构建编译,输出目录默认dist/') 7 | .option('-a, --analyzer [page]', '编译构建打包分析'); 8 | 9 | const build = (page) => { 10 | const { build } = require('../lib/build'); 11 | if (page == 'true') { 12 | process.env.NODE_ENV = 'production'; 13 | page = JSON.parse(page); 14 | } else if (page == 'false') { 15 | process.env.NODE_ENV = 'development'; 16 | page = JSON.parse(page); 17 | } else { 18 | process.env.NODE_ENV = 'production'; 19 | } 20 | build(page); 21 | }; 22 | 23 | // webpack build bundle 24 | commander.command('build [page]').action((page = true) => { 25 | build(page); 26 | }); 27 | 28 | // Analyzer webpack build bundle 29 | commander.command('analyzer [page]').action((page = true) => { 30 | process.argv.push('--analyzer'); 31 | build(page); 32 | }); 33 | 34 | // start with webpack-dev-server with csr 35 | commander.command('dev [page]').action((page = true) => { 36 | const { dev } = require('../lib/dev'); 37 | process.env.NODE_ENV = 'development'; 38 | dev(page); 39 | }); 40 | 41 | commander.parse(process.argv); 42 | -------------------------------------------------------------------------------- /doc/react/webpackconfig.md: -------------------------------------------------------------------------------- 1 | 2 | # webpack 3 | 4 | srejs基于webpack@4.0+,Bable@7.0+进行项目编译,默认集成配置项如下 5 | 6 | ## loader 7 | 8 | - babel-loader 9 | - less-loader 10 | - css-loader 11 | - sass-loader 12 | - postcss-loader 13 | - url-loader 14 | 15 | ## alias默认别名 16 | 17 | ```js 18 | alias: { 19 | @: rootDir, 20 | components: rootDir + '/components', 21 | images: rootDir + '/images', 22 | } 23 | ``` 24 | 25 | ## DefinePlugin 26 | 27 | 开发者在js中通过`process.env.NODE_ENV`可以进行环境的区分。 28 | 29 | ```shell 30 | 'process.env': NODE_ENV: JSON.stringify(dev ? 'development' : 'production') 31 | ``` 32 | 33 | # 覆盖或者新增webpack配置 34 | 35 | srejs支持自定义webpack配置,在项目根目录下创建webpack.config.js。文件支持导出对象或者函数。 36 | 37 | - 函数 【推荐】 38 | 函数接受两个参数,第一个为框架内置webpack配置对象;第二个参数可区分ssr和csr模式。 39 | 40 | ```js 41 | module.exports = (configureWebpack, type) => { 42 | if (type == 'ssr') { 43 | //服务端渲染配置 44 | } else if (type === 'csr') { 45 | //客户端构建配置 46 | // configureWebpack.module.rules[0].exclude = /\/node_module\/!(antd.*)/; 47 | } 48 | 49 | return configureWebpack; 50 | }; 51 | ``` 52 | 53 | - 对象 54 | 对象配置属性将通过webpack-merge和框架内置属性进行合并。此方法适用于同时设置客户端和服务端渲染模式相同的配置。 55 | 56 | ```js 57 | module.exports = { 58 | // module 59 | module:{ 60 | rules:[ 61 | // other loader 62 | ] 63 | } 64 | } 65 | 66 | ``` 67 | -------------------------------------------------------------------------------- /doc/vue/vuex.md: -------------------------------------------------------------------------------- 1 | # 使用Vuex 2 | 3 | > 当项目比较复杂时,我们可以在页面组件入口文件中导出Vuex store对象。框架会自动从根页面组件注入vue子组件中,通过$store访问到实例化后的store。 4 | 5 | ```js 6 | import App from './App.vue'; 7 | export default { 8 | App, 9 | Store: { 10 | state: { 11 | count: 100, 12 | }, 13 | mutations: { 14 | increment: (state) => state.count++, 15 | decrement: (state) => state.count--, 16 | }, 17 | }, 18 | }; 19 | ``` 20 | 21 | 框架接收到Store对象后,会实例化vuex。并且初始化到vue实例中,通过vue.use注入到全局。对于初始化的state数据,如果在initProps中也传入同名的属性,则initProps.state将会覆盖主入口文件传入store.state中的属性值。 22 | 23 | ## 服务端初始化state 24 | 25 | ```js 26 | Sre.render(ctx,'vuex',{state:{count:200}}); 27 | ``` 28 | 29 | ## 页面组件获取状态 30 | 31 | ```vue 32 | 41 | 42 | 60 | ``` 61 | 62 | 最后展示到页面上的`count`初始值为:`200` 63 | -------------------------------------------------------------------------------- /doc/vue3/vuex.md: -------------------------------------------------------------------------------- 1 | # 使用Vuex 2 | 3 | > 当项目比较复杂时,我们可以在页面组件入口文件中导出Vuex store对象。框架会自动从根页面组件注入vue子组件中,通过$store访问到实例化后的store。 4 | 5 | ```js 6 | import App from './App.vue'; 7 | export default { 8 | App, 9 | Store: { 10 | state: { 11 | count: 100, 12 | }, 13 | mutations: { 14 | increment: (state) => state.count++, 15 | decrement: (state) => state.count--, 16 | }, 17 | }, 18 | }; 19 | ``` 20 | 21 | 框架接收到Store对象后,会实例化vuex。并且初始化到vue实例中,通过vue.use注入到全局。对于初始化的state数据,如果在initProps中也传入同名的属性,则initProps.state将会覆盖主入口文件传入store.state中的属性值。 22 | 23 | ## 服务端初始化state 24 | 25 | ```js 26 | Sre.render(ctx,'vuex',{state:{count:200}}); 27 | ``` 28 | 29 | ## 页面组件获取状态 30 | 31 | ```vue 32 | 41 | 42 | 60 | ``` 61 | 62 | 最后展示到页面上的`count`初始值为:`200` 63 | -------------------------------------------------------------------------------- /packages/app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/common/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/react/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/vue-webpack/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/react-webpack/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/vue3-webpack/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react","prettier","react-hooks" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion":6, 8 | "sourceType":"module", 9 | "ecmaFeatures": 10 | { 11 | "jsx":true, 12 | "experimentalObjectRestSpread":true, 13 | "modules":true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "amd": true, 19 | "es6": true, 20 | "node": true, 21 | "mocha": true 22 | }, 23 | "rules": { 24 | "comma-dangle": 1, 25 | "quotes": [ 0, "single" ], 26 | "no-undef":"error", 27 | "global-strict": 0, 28 | "no-extra-semi": 1, 29 | "no-underscore-dangle": 0, 30 | "no-console": 0, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "no-alert": 0, 35 | "react/jsx-uses-react": 1, 36 | "react/jsx-uses-vars": 1, 37 | "react-hooks/rules-of-hooks": "error", 38 | "prettier/prettier":["error",{ 39 | "printWidth": 100, 40 | "tabWidth": 4, 41 | "semi": true, 42 | "trailingComma": "none", 43 | "singleQuote": true, 44 | "bracketSpacing": true, 45 | "jsxBracketSameLine": true 46 | }] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/slider/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Swiper from 'react-id-swiper'; 3 | import { ItemMapArr } from '../../interface'; 4 | import 'swiper/swiper.less'; 5 | import './index.less'; 6 | 7 | interface Props { 8 | data: ItemMapArr[], 9 | [key:string]:any 10 | } 11 | 12 | const params = { 13 | pagination: { 14 | el: '.swiper-pagination', 15 | clickable: true, 16 | loop: true, 17 | }, 18 | }; 19 | 20 | function Slider(props: Props) { 21 | const data = props.data[0]; 22 | 23 | return ( 24 |
25 | 26 | { 27 | data.itemMap.map((val) => ( 28 |
props.history.push('/detail/cbba934b14f747049187')}> 29 | 30 |
31 | 32 | {val.title} 33 | 34 |
35 |
36 | )) 37 | } 38 |
39 |
40 | ); 41 | } 42 | 43 | export default Slider; 44 | -------------------------------------------------------------------------------- /packages/app-vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-vue3", 3 | "version": "1.4.1", 4 | "description": "", 5 | "private": true, 6 | "main": "app.js", 7 | "scripts": { 8 | "build": "srejs build", 9 | "start": "node start.js", 10 | "dev": "srejs dev", 11 | "analyzer": "srejs analyzer" 12 | }, 13 | "dependencies": { 14 | "@babel/core": "^7.14.0", 15 | "@babel/plugin-transform-modules-commonjs": "^7.7.5", 16 | "@babel/plugin-transform-runtime": "^7.7.6", 17 | "@babel/preset-env": "^7.7.4", 18 | "@babel/preset-typescript": "^7.22.5", 19 | "@babel/register": "^7.22.5", 20 | "@babel/runtime": "^7.7.7", 21 | "@srejs/vue3": "^1.4.1", 22 | "babel-loader": "^8.2.2", 23 | "core-js": "^3.11.0", 24 | "css-hot-loader": "^1.4.4", 25 | "css-loader": "^5.2.4", 26 | "es6-promise": "^4.2.8", 27 | "file-loader": "^6.2.0", 28 | "koa": "^2.13.1", 29 | "less": "^4.1.1", 30 | "less-loader": "^4.0.5", 31 | "lodash": "^4.17.21", 32 | "postcss-loader": "^4.0.4", 33 | "sass": "^1.39.2", 34 | "sass-loader": "^7.2.0", 35 | "stylus": "^0.54.8", 36 | "stylus-loader": "^4.3.3", 37 | "url-loader": "^4.1.1", 38 | "vue": "^3.2.19", 39 | "vue-loader": "^16.8.1", 40 | "vue-router": "^4.0.11", 41 | "vue-style-loader": "^4.1.3", 42 | "vuex": "^4.0.2", 43 | "webpack": "^4.35.0", 44 | "webpack-hot-middleware": "^2.25.0" 45 | }, 46 | "author": "", 47 | "license": "ISC", 48 | "devDependencies": { 49 | "@types/lodash": "^4.14.170" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/rectangle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './index.less'; 3 | 4 | function Rectangle(props) { 5 | const data = props.data[0]; 6 | 7 | return ( 8 |
9 | { 10 | data.itemMap.map((val) => { 11 | const imgUrl = val.img; 12 | 13 | return ( 14 |
{ 15 | // eslint-disable-next-line no-undef 16 | location.href = '/ykfe/detail/cbba934b14f747049187'; 17 | }}> 18 |
19 |
22 |
23 | { val.title } 24 |
25 |
26 | {val.subtitle} 27 |
28 |
29 |
30 | ); 31 | }) 32 | } 33 |
34 | ); 35 | } 36 | 37 | export default Rectangle; 38 | -------------------------------------------------------------------------------- /packages/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.4.0", 4 | "description": "", 5 | "private": true, 6 | "main": "app.js", 7 | "scripts": { 8 | "link": "yarn link react react-dom react-router-dom", 9 | "build": "srejs build", 10 | "start": "node start.js", 11 | "dev": "srejs dev" 12 | }, 13 | "sideEffects": [ 14 | "*.less", 15 | "*.scss", 16 | "*.css" 17 | ], 18 | "dependencies": { 19 | "@babel/core": "^7.14.0", 20 | "@babel/plugin-transform-modules-commonjs": "^7.7.5", 21 | "@babel/plugin-transform-runtime": "^7.7.6", 22 | "@babel/preset-env": "^7.7.4", 23 | "@babel/preset-react": "^7.7.4", 24 | "@babel/preset-typescript": "^7.22.5", 25 | "@babel/register": "^7.22.5", 26 | "@babel/runtime": "^7.22.10", 27 | "@srejs/react": "^1.4.0", 28 | "antd": "^4.16.3", 29 | "babel-loader": "^8.2.2", 30 | "core-js": "^3.11.0", 31 | "css-hot-loader": "^1.4.4", 32 | "css-loader": "^5.2.4", 33 | "file-loader": "^6.2.0", 34 | "koa": "^2.13.1", 35 | "less": "^4.1.1", 36 | "less-loader": "^4.0.5", 37 | "lodash": "^4.17.21", 38 | "postcss-loader": "^4.0.4", 39 | "react-sticky": "^6.0.3", 40 | "sass": "^1.39.2", 41 | "sass-loader": "^7.2.0", 42 | "url-loader": "^4.1.1", 43 | "webpack-hot-middleware": "^2.25.0" 44 | }, 45 | "author": "", 46 | "license": "ISC", 47 | "devDependencies": { 48 | "@types/lodash": "^4.14.170", 49 | "@types/react": "^17.0.11", 50 | "@types/react-sticky": "^6.0.3" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/app-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-vue", 3 | "version": "1.4.2", 4 | "description": "", 5 | "private": true, 6 | "main": "app.js", 7 | "scripts": { 8 | "build": "srejs build", 9 | "start": "node start.js", 10 | "dev": "srejs dev", 11 | "analyzer": "srejs analyzer" 12 | }, 13 | "dependencies": { 14 | "@babel/core": "^7.14.0", 15 | "@babel/plugin-transform-modules-commonjs": "^7.7.5", 16 | "@babel/plugin-transform-runtime": "^7.7.6", 17 | "@babel/preset-env": "^7.7.4", 18 | "@babel/preset-typescript": "^7.22.5", 19 | "@babel/register": "^7.22.5", 20 | "@babel/runtime": "^7.22.10", 21 | "@srejs/vue": "^1.4.2", 22 | "babel-loader": "^8.2.2", 23 | "core-js": "^3.11.0", 24 | "css-hot-loader": "^1.4.4", 25 | "css-loader": "^5.2.4", 26 | "es6-promise": "^4.2.8", 27 | "file-loader": "^6.2.0", 28 | "koa": "^2.13.1", 29 | "less": "^4.1.1", 30 | "less-loader": "^4.0.5", 31 | "lodash": "^4.17.21", 32 | "postcss-loader": "^4.0.4", 33 | "sass": "^1.39.2", 34 | "sass-loader": "^7.2.0", 35 | "stylus": "^0.54.8", 36 | "stylus-loader": "^4.3.3", 37 | "url-loader": "^4.1.1", 38 | "vue": "^2.6.14", 39 | "vue-loader": "^15.9.7", 40 | "vue-router": "^3.5.2", 41 | "vuex": "^3.6.2", 42 | "webpack": "^4.35.0", 43 | "webpack-hot-middleware": "^2.25.0" 44 | }, 45 | "author": "", 46 | "license": "ISC", 47 | "devDependencies": { 48 | "@types/lodash": "^4.14.170", 49 | "vue-template-compiler": "^2.6.14" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/brief/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BriefDataNode } from '../../interface'; 3 | import './index.less'; 4 | 5 | interface Props { 6 | data: BriefDataNode[] 7 | } 8 | function Brief(props: Props) { 9 | const { data } = props.data[0]; 10 | 11 | return ( 12 |
13 |
14 | {data.mark.data.text} 15 |

{data.showName}

16 |
17 |
18 | { 19 | data.subTitleList.map((item, index) => ( 20 | item.subtitle && ( 21 | 22 | { 23 | // eslint-disable-next-line no-nested-ternary 24 | item.subtitleType === 'PLAY_VV' 25 | ? 26 | : (index > 0) ? (/) : '' 27 | } 28 | {item.subtitle} 29 | 30 | ) 31 | )) 32 | } 33 |
34 |
35 | ); 36 | } 37 | 38 | export default Brief; 39 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/common.less: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | a { 7 | color: #fff; 8 | text-decoration: none; 9 | } 10 | 11 | ul { 12 | list-style: none; 13 | } 14 | html{ 15 | font-size: 100px; 16 | } 17 | 18 | :global { 19 | .loading { 20 | width: 30px; 21 | height: 30px; 22 | .verticalLevelCenter 23 | } 24 | } 25 | .verticalCenter { 26 | position: absolute; 27 | top: 50%; 28 | transform: translate(0, -50%) 29 | } 30 | .levelCenter { 31 | position: absolute; 32 | left: 50%; 33 | transform: translate(-50%, 0) 34 | } 35 | .verticalLevelCenter { 36 | position: absolute; 37 | left: 50%; 38 | top: 50%; 39 | transform: translate(-50%, -50%) 40 | } 41 | .verticalCenterFlex { 42 | display: flex; 43 | align-items: center; 44 | } 45 | .levelCenterFlex { 46 | display: flex; 47 | justify-content: center; 48 | } 49 | .verticalLevelCenterFlex { 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | } 54 | .overflowEllipsis { 55 | overflow: hidden; 56 | text-overflow:ellipsis; 57 | white-space: nowrap; 58 | } 59 | .pName { 60 | font-size: 15px; 61 | color: #000000; 62 | margin-top: 10px; 63 | padding-left: 9px; 64 | overflow: hidden; 65 | white-space: nowrap; 66 | text-overflow: ellipsis; 67 | height: 25px; 68 | line-height: 25px; 69 | z-index: 99; 70 | } 71 | .pDesc { 72 | padding-left: 9px; 73 | font-size: 13px; 74 | color: #999999; 75 | margin-bottom: 20px; 76 | overflow: hidden; 77 | white-space: nowrap; 78 | text-overflow: ellipsis; 79 | z-index: 99; 80 | } -------------------------------------------------------------------------------- /example/uma-css-module/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | srejs 15 | 16 | 17 | 18 |
19 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/app/web/pages/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | srejs 15 | 16 | 17 | 18 |
19 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | srejs 15 | 16 | 17 | 18 |
19 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import { Counter } from './features/counter/Counter'; 4 | import './App.css'; 5 | 6 | function App() { 7 | return ( 8 |
9 |
10 | logo 11 | 12 |

13 | Edit src/App.js and save to reload. 14 |

15 | 16 | Learn 17 | 23 | React 24 | 25 | , 26 | 32 | Redux 33 | 34 | , 35 | 41 | Redux Toolkit 42 | 43 | , and 44 | 50 | React Redux 51 | 52 | 53 |
54 |
55 | ); 56 | } 57 | 58 | export default App; 59 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/features/counter/Counter.module.css: -------------------------------------------------------------------------------- 1 | .row { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | .row > button { 8 | margin-left: 4px; 9 | margin-right: 8px; 10 | } 11 | .row:not(:last-child) { 12 | margin-bottom: 16px; 13 | } 14 | 15 | .value { 16 | font-size: 78px; 17 | padding-left: 16px; 18 | padding-right: 16px; 19 | margin-top: 2px; 20 | font-family: 'Courier New', Courier, monospace; 21 | } 22 | 23 | .button { 24 | appearance: none; 25 | background: none; 26 | font-size: 32px; 27 | padding-left: 12px; 28 | padding-right: 12px; 29 | outline: none; 30 | border: 2px solid transparent; 31 | color: rgb(112, 76, 182); 32 | padding-bottom: 4px; 33 | cursor: pointer; 34 | background-color: rgba(112, 76, 182, 0.1); 35 | border-radius: 2px; 36 | transition: all 0.15s; 37 | } 38 | 39 | .textbox { 40 | font-size: 32px; 41 | padding: 2px; 42 | width: 64px; 43 | text-align: center; 44 | margin-right: 4px; 45 | } 46 | 47 | .button:hover, 48 | .button:focus { 49 | border: 2px solid rgba(112, 76, 182, 0.4); 50 | } 51 | 52 | .button:active { 53 | background-color: rgba(112, 76, 182, 0.2); 54 | } 55 | 56 | .asyncButton { 57 | composes: button; 58 | position: relative; 59 | } 60 | 61 | .asyncButton:after { 62 | content: ''; 63 | background-color: rgba(112, 76, 182, 0.15); 64 | display: block; 65 | position: absolute; 66 | width: 100%; 67 | height: 100%; 68 | left: 0; 69 | top: 0; 70 | opacity: 0; 71 | transition: width 1s linear, opacity 0.5s ease 1s; 72 | } 73 | 74 | .asyncButton:active:after { 75 | width: 0%; 76 | opacity: 1; 77 | transition: 0s; 78 | } 79 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <%= htmlWebpackPlugin.options.title %> 15 | 16 | 17 | 18 |
19 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@srejs/common", 3 | "version": "1.4.0", 4 | "description": "Srejs是一个轻量级服务端渲染骨架工具,为koa社区的nodejs开发框架提供具有服务端渲染能力的工具包,使得类似umajs类的web开发框架可以更方便实现前后端同构的服务端渲染能力。特点:轻量级,模板式调用页面进行服务端渲染,不限制后端路由。", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "files": [ 10 | "bin", 11 | "lib", 12 | "index.d.ts" 13 | ], 14 | "keywords": [ 15 | "ssr", 16 | "react", 17 | "@umajs/plugin-react-ssr", 18 | "umajs-react-ssr", 19 | "@srejs" 20 | ], 21 | "scripts": { 22 | "build": "babel src --out-dir lib --copy-files", 23 | "start": "babel src --watch --out-dir lib --source-maps inline --copy-files", 24 | "watch": "babel src --watch --out-dir lib --source-maps inline --copy-files", 25 | "prepublish": "npm run build" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git@github.com:dazjean/srejs.git" 30 | }, 31 | "publishConfig": { 32 | "registry": "https://registry.npmjs.org", 33 | "access": "public" 34 | }, 35 | "bugs": { 36 | "url": "https://github.com/dazjean/srejs/issues" 37 | }, 38 | "homepage": "https://github.com/dazjean/srejs#readme", 39 | "license": "MIT", 40 | "dependencies": { 41 | "koa-send": "^5.0.0", 42 | "koa-webpack-middleware": "^1.0.7", 43 | "ora": "^5.4.1", 44 | "react": "^17.0.2", 45 | "react-dom": "^17.0.2", 46 | "react-router-dom": "^5.2.0", 47 | "webpack-hot-middleware": "^2.25.0" 48 | }, 49 | "gitHead": "da596c6a49044e00ebdbb45cb25841e2fbeb3b83", 50 | "devDependencies": { 51 | "@babel/cli": "^7.22.10", 52 | "@babel/core": "^7.22.10", 53 | "@babel/plugin-transform-modules-commonjs": "^7.14.5", 54 | "@babel/plugin-transform-runtime": "^7.22.10", 55 | "@babel/preset-env": "^7.22.10" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /doc/react/typescript.md: -------------------------------------------------------------------------------- 1 | # 使用typescript 2 | `Srejs` 默认使用`babel-loader`搭配插件`@babel/preset-typescript`进行ts编译,但不做类型校验,类型校验可以使用ts或者`vs code`插件 3 | 4 | ## 安装typescript 5 | ``` 6 | yarn add typescript; 7 | ``` 8 | 9 | ## 新增tsconfig.json 10 | 11 | ```js 12 | // web/tsconfig.json 13 | { 14 | "compilerOptions": { 15 | "jsx": "react", 16 | // Target latest version of ECMAScript. 17 | "target": "esnext", 18 | // Search under node_modules for non-relative imports. 19 | "moduleResolution": "node", 20 | // Process & infer types from .js files. 21 | "allowJs": true, 22 | // Don't emit; allow Babel to transform files. 23 | "noEmit": true, 24 | // Enable strictest settings like strictNullChecks & noImplicitAny. 25 | "strict": true, 26 | // Disallow features that require cross-file information for emit. 27 | "isolatedModules": true, 28 | // Import non-ES modules as default imports. 29 | "esModuleInterop": true 30 | }, 31 | "include": ["web"] 32 | } 33 | 34 | ``` 35 | 36 | ## 创建页面组件 37 | 38 | ```ts 39 | // web/pages/list/index.tsx 40 | 41 | import React from 'react'; 42 | type typeProps = { 43 | ListData :[string] 44 | } 45 | export default function (props:typeProps){ 46 | const {ListData} = props; 47 | return ( 48 |
49 |

列表

50 |
    51 | {ListData.map((item,value)=>{ 52 | return ( 53 |
  • 54 |
    {item}
    55 |
  • 56 | ) 57 | })} 58 |
59 |
60 | ) 61 | } 62 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "scripts": { 5 | "clearn":"del -f packages/*/yarn.lock && del -f packages/*/node_modules && del -f packages/*/lib", 6 | "init": "del -f packages/*/yarn.lock && del -f packages/*/node_modules && del -f packages/*/lib && lerna bootstrap", 7 | "prepublish": "lerna run test && lerna run lint && lerna run build", 8 | "publish": "lerna publish", 9 | "watch":"lerna run watch", 10 | "postinstall": "npm run lint && npx checker-init && npm run init && npm run linkReact && npm run linkReactDom && npm run linkReactRouter && npm run linkVue && npm run linkApp && npm run linkVueNext", 11 | "linkApp": "cd packages/app && npm run link ", 12 | "linkVueNext": "cd packages/vue3 && npm run link ", 13 | "linkReact": "cd packages/react/node_modules/react && yarn link", 14 | "linkReactDom": "cd packages/react/node_modules/react-dom && yarn link", 15 | "linkReactRouter": "cd packages/react/node_modules/react-router-dom && yarn link", 16 | "linkVue": "cd packages/app-vue3/node_modules/vue && yarn link", 17 | "linkVuex": "cd packages/app-vue3/node_modules/vuex && yarn link", 18 | "linkVueRouter": "cd packages/app-vue3/node_modules/vue-router && yarn link", 19 | "lint": "eslint packages/*/src --fix" 20 | }, 21 | "devDependencies": { 22 | "commit-msg-checker": "^1.0.8", 23 | "del-cli": "^3.0.1", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-react": "^7.23.2", 26 | "eslint-plugin-react-hooks": "^4.2.0", 27 | "lerna": "^4.0.0", 28 | "prettier": "^2.3.0" 29 | }, 30 | "dependencies": { 31 | "babel-eslint": "^10.1.0", 32 | "eslint": "^7.26.0" 33 | }, 34 | "msgChecker":{ 35 | "ignore": "^v([1-9])" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/uma-react-redux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.2", 4 | "description": "umajs+srejs+react-redux", 5 | "author": "dazjean", 6 | "license": "ISC", 7 | "directories": { 8 | "lib": "lib", 9 | "test": "__tests__" 10 | }, 11 | "files": [ 12 | "lib", 13 | "index.d.ts" 14 | ], 15 | "publishConfig": { 16 | "registry": "https://registry.npmjs.org" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Umajs/Uma.git" 21 | }, 22 | "scripts": { 23 | "lint": "eslint src --ext .ts", 24 | "lint-w": "esw src --clear --color -w --ext .ts", 25 | "dev": "ts-node-dev --respawn src/app.ts", 26 | "start": "run-p dev lint-w", 27 | "prebuild": "npm run lint", 28 | "build": "tsc", 29 | "preprod": "npm run build", 30 | "prod": "node app/app.js --production" 31 | }, 32 | "dependencies": { 33 | "@reduxjs/toolkit": "^1.5.1", 34 | "@umajs/core": "^1.1.2", 35 | "@umajs/plugin-react-ssr": "^1.0.5", 36 | "@umajs/router": "^1.1.2", 37 | "koa": "^2.11.0", 38 | "react": "^17.0.2", 39 | "react-dom": "^17.0.2", 40 | "react-redux": "^7.2.4", 41 | "react-router-dom": "^5.2.0" 42 | }, 43 | "devDependencies": { 44 | "@types/koa": "^2.0.48", 45 | "@types/koa-views": "^2.0.3", 46 | "@typescript-eslint/eslint-plugin": "^2.33.0", 47 | "@typescript-eslint/parser": "^2.33.0", 48 | "eslint": "^7.0.0", 49 | "eslint-config-airbnb-base": "^14.1.0", 50 | "eslint-plugin-import": "^2.20.2", 51 | "eslint-plugin-typescript": "^0.14.0", 52 | "eslint-watch": "^6.0.1", 53 | "npm-run-all": "^4.1.5", 54 | "ts-node": "^8.2.0", 55 | "ts-node-dev": "^1.0.0-pre.32", 56 | "typescript": "^3.2.2" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /doc/vue/seoHtml.md: -------------------------------------------------------------------------------- 1 | # SEO和HTML 2 | 在`initProps`中通过,默认接收`title,keywords,description`作为页面标题,关键字,网页描述填充字段。 3 | 4 | ```js 5 | Sre.render(ctx,'list',{title:'xxx',keywords:'xxx',description:'xxxx'}); 6 | ``` 7 | 8 | ## 自定义html 9 | 10 | 框架内置`HTMLWebpackPlugin`插件,开发者在页面组件同级目录下可以覆盖默认html模板自定义引入第三方资源和脚本。自定义html文件名为页面下的`index.html`。 11 | 12 | ```html 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | vue ssr 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | 在html模板中,还可以使用模板插值。服务端渲染初始化时传递的`initProps`数据在服务端渲染时会被注入为`渲染上下文对象`。 36 | 37 | ```html 38 | 39 | 40 | 41 | {{ title }} 42 | 43 | 44 | {{{ meta }}} 45 | 46 | 47 | 48 | 49 | 50 | ``` 51 | 52 | ## 支持全局HTML 53 | 54 | 为满足业务引入第三方脚本也提供了以下方式自定义html模板。 55 | 56 | - `web/pages/xxx/index.html`(局部页面生效) 57 | - `web/index.html`(全局生效) 58 | 59 | **优先级**`web/pages/xxx/index.html` > `web/index.html` 60 | -------------------------------------------------------------------------------- /doc/vue3/seoHtml.md: -------------------------------------------------------------------------------- 1 | # SEO和HTML 2 | 3 | 在`initProps`中通过,默认接收`title,keywords,description`作为页面标题,关键字,网页描述填充字段。 4 | 5 | ```js 6 | Sre.render(ctx,'list',{title:'xxx',keywords:'xxx',description:'xxxx'}); 7 | ``` 8 | 9 | ## 自定义html 10 | 11 | 框架内置`HTMLWebpackPlugin`插件,开发者在页面组件同级目录下可以覆盖默认html模板自定义引入第三方资源和脚本。自定义html文件名为页面下的`index.html`。 12 | 13 | ```html 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | vue ssr 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | ``` 35 | 36 | 在html模板中,还可以使用模板插值。服务端渲染初始化时传递的`initProps`数据在服务端渲染时会被注入为`渲染上下文对象`。 37 | 38 | ```html 39 | 40 | 41 | 42 | {{ title }} 43 | 44 | 45 | {{{ meta }}} 46 | 47 | 48 | 49 | 50 | 51 | ``` 52 | 53 | ## 支持全局HTML 54 | 55 | 为满足业务引入第三方脚本也提供了以下方式自定义html模板。 56 | 57 | - `web/pages/xxx/index.html`(局部页面生效) 58 | - `web/index.html`(全局生效) 59 | 60 | **优先级**`web/pages/xxx/index.html` > `web/index.html` 61 | -------------------------------------------------------------------------------- /packages/react/src/initialProps.js: -------------------------------------------------------------------------------- 1 | import common, { SSRKEY, Logger } from '@srejs/common'; 2 | 3 | export function getDisplayName(Component) { 4 | return typeof Component === 'string' 5 | ? Component 6 | : Component.displayName || Component.name || 'Unknown'; 7 | } 8 | export async function loadGetInitialProps(App, ctx) { 9 | if (!App.getInitialProps) { 10 | return {}; 11 | } 12 | if (common.isDev()) { 13 | if (App.prototype && App.prototype.getInitialProps) { 14 | const message = `"${getDisplayName( 15 | App 16 | )}.getInitialProps(ctx ,query,pathname)" is defined as an instance method`; 17 | throw new Error(message); 18 | } 19 | } 20 | // when npm run output ctx is null 21 | ctx = ctx || {}; 22 | 23 | const res = ctx.res || (ctx.ctx && ctx.ctx.res); 24 | 25 | const props = await App.getInitialProps( 26 | ctx, 27 | (ctx[SSRKEY] && ctx[SSRKEY].query) || null, 28 | (ctx[SSRKEY] && ctx[SSRKEY].pathname) || null 29 | ); 30 | 31 | if (res && (res.finished || res.headersSent)) { 32 | return props; 33 | } 34 | 35 | if (!props) { 36 | const message = `"${getDisplayName( 37 | App 38 | )}.getInitialProps()" should resolve to an object. But found "${props}" instead.`; 39 | throw new Error(message); 40 | } 41 | 42 | if (common.isDev()) { 43 | if (Object.keys(props).length === 0 && !ctx.ctx) { 44 | Logger.warn( 45 | `${getDisplayName( 46 | App 47 | )} returned an empty object from \`getInitialProps\`. This de-optimizes and prevents automatic static optimization` 48 | ); 49 | } 50 | } 51 | 52 | return props; 53 | } 54 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/web/components/search/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { IData, MixStateAndDispatch } from '../../interface'; 3 | import Context from '../../context'; 4 | 5 | import style from './index.module.less'; 6 | 7 | interface SearchState extends IData { 8 | search?: { 9 | text: string 10 | } 11 | } 12 | // 参考本组件学习如何使用 useContext 来跨组件/页面共享状态 13 | function Search() { 14 | const { state, dispatch } = useContext>(Context); 15 | // eslint-disable-next-line no-undef 16 | const handleChange = (e: React.ChangeEvent) => { 17 | dispatch?.({ 18 | type: 'updateContext', 19 | payload: { 20 | search: { 21 | text: e.target.value, 22 | }, 23 | }, 24 | }); 25 | }; 26 | 27 | const toSearch = () => { 28 | const searchVal = state?.search?.text ?? ''; 29 | 30 | // eslint-disable-next-line no-restricted-globals 31 | // eslint-disable-next-line no-undef 32 | location.href = `https://search.youku.com/search_video?keyword=${searchVal}`; 33 | }; 34 | 35 | return ( 36 |
37 | {/* 这里需要给 value 一个兜底的状态 否则 context 改变 首次 render 的 text 值为 undefined 会导致 input 组件 unmount */} 38 | {/* ref: https://stackoverflow.com/questions/47012169/a-component-is-changing-an-uncontrolled-input-of-type-text-to-be-controlled-erro/47012342 */} 39 | 40 | 41 |
42 | ); 43 | } 44 | 45 | export default Search; 46 | -------------------------------------------------------------------------------- /doc/react/initprops.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### 服务端获取initProps(推荐) 4 | > 当前前后端的交互不一定是http,而是rpc框架或者直接从数据库中获取并加工获得。这种方式就存在很大的局限,一是不方便node调试,而是必须使用http作为前后端交互通信方式,而且这种将node环境和客户端页面组件混写在一起的方式也会增加开发人员的理解,所以我们建议使用服务端直接获取方式。 5 | 6 | 7 | ```js 8 | // 服务端路由 9 | import Koa from 'koa'; 10 | import srejs from '@srejs/react'; 11 | const app = new Koa(); 12 | const Sre = new srejs(app,process.env.NODE_ENV != 'production',false); 13 | app.use(async (ctx,next)=>{ 14 | if(ctx.path==="/list"){ 15 | // ListData将作为list页面组件初始props属性在react组件中被接收。 16 | const html = await Sre.render(ctx,'list',{ListData:['item1','item2','item3','item4',]}); 17 | 18 | ctx.type = 'text/html'; 19 | ctx.body = html; 20 | }else{ 21 | await next(); 22 | } 23 | }) 24 | 25 | // 客户端页面组件 26 | export default function (props:typeProps){ 27 | const {ListData} = props; 28 | return ( 29 |
30 |

List

31 |
    32 | {ListData.map((item,value)=>{ 33 | return ( 34 |
  • 35 |
    {item}
    36 |
  • 37 | ) 38 | })} 39 |
40 |
41 | ) 42 | } 43 | ``` 44 | 45 | 46 | 47 | ### 静态方法getInitialProps(不建议) 48 | 49 | > getInitialProps静态方法是由`nextjs`提出的概念,是在组件实例中挂载一个static静态方法,当服务渲染时预先调用此方法获取到数据,然后再SSR阶段通过props初始化到页面组件中,从而得到完整的html结果。这种方案也被业内其他框架追随,包括`egg-react-ssrs` `ykfe/ssr` `easy-team`等。 50 | 51 | ```js 52 | function Page(props) { 53 | return
{props.name}
54 | } 55 | 56 | Page.getInitialProps = async (ctx) => { 57 | return Promise.resolve({ 58 | name: 'Srejs + React + SSR', 59 | }) 60 | } 61 | 62 | export default Page 63 | ``` -------------------------------------------------------------------------------- /packages/app/web/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | //sass style 2 | //------------------------------- 3 | @use "sass:math"; 4 | 5 | $baseFontSize: 32px !default; 6 | 7 | 8 | // pixels to rems 9 | @function pxToRem($px) { 10 | @return math.div($px, $baseFontSize) * 1rem; 11 | } 12 | body, 13 | div, 14 | dl, 15 | dt, 16 | dd, 17 | ul, 18 | ol, 19 | li, 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | h5, 25 | h6, 26 | pre, 27 | form, 28 | fieldset, 29 | input, 30 | textarea, 31 | p, 32 | blockquote, 33 | th, 34 | td, 35 | header, 36 | img 37 | { 38 | margin: 0; 39 | padding: 0; 40 | font-family: '微软雅黑'; 41 | } 42 | .clearfix:after { 43 | content: "."; 44 | display: block; 45 | height: 0; 46 | clear: both; 47 | visibility: hidden; 48 | } 49 | 50 | img{ 51 | display: block; 52 | } 53 | input{ 54 | border: none; 55 | outline: none; 56 | } 57 | li{ 58 | list-style: none; 59 | } 60 | 61 | html,body,#app{ 62 | height: 100%; 63 | width: 100%; 64 | font-size: 16px; 65 | overflow-y: auto; 66 | } 67 | *{ 68 | -webkit-tap-highlight-color:transparent; 69 | -webkit-overflow-scrolling:touch; 70 | } 71 | .home{ 72 | width: 100%; 73 | height: 100%; 74 | margin: 0 auto; /*水平居中*/ 75 | padding-top: 70px; 76 | position: relative; 77 | top: 50%; /*偏移*/ 78 | transform: translateY(-50%); 79 | background-image: url('@/images/srejs.png'); 80 | background-size: auto; 81 | background-position: top; 82 | background-repeat: no-repeat; 83 | font-weight: bold; 84 | font-size: $baseFontSize; 85 | li a{ 86 | color:#03a9f4; 87 | } 88 | .title,.footer{ 89 | color:#000000; 90 | font-size: pxToRem(18px); 91 | } 92 | .footer{ 93 | text-align: center; 94 | a{ 95 | color: #000000 !important; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /doc/vue/suport-css.md: -------------------------------------------------------------------------------- 1 | # 内置css支持 2 | 3 | > 框架内置了`vue-style-loader`以及css预处理器loader,支持`*.vue`单个文件组件内的 ` 20 | ``` 21 | 22 | ## 预处理器less/scss 23 | 24 | ```vue 25 | 30 | 31 | 37 | 38 | 44 | ``` 45 | 46 | **当我们采用*.less或者*.scss文件编写样式时,也可以从 JavaScript 中导入 CSS,例如,import './foo.css'** 47 | 48 | ## CSS Modules 49 | 50 | - 使用style module 51 | 52 | 在你的 ` 69 | ``` 70 | 71 | **详细原理查看官方文档[vue-loader](https://vue-loader.vuejs.org/zh/guide/css-modules.html#css-modules)** 72 | 73 | - 使用预处理器样 74 | 75 | 如果你的样式是从JavaScript中导入的,那么你只需要将把文件命名为`*.module.(less|scss|css)`。 76 | 77 | ```vue 78 | 85 | 86 | 94 | ``` 95 | -------------------------------------------------------------------------------- /doc/vue3/suport-css.md: -------------------------------------------------------------------------------- 1 | # 内置css支持 2 | 3 | > 框架内置了`vue-style-loader`以及css预处理器loader,支持`*.vue`单个文件组件内的 ` 20 | ``` 21 | 22 | ## 预处理器less/scss 23 | 24 | ```vue 25 | 30 | 31 | 37 | 38 | 44 | ``` 45 | 46 | **当我们采用*.less或者*.scss文件编写样式时,也可以从 JavaScript 中导入 CSS,例如,import './foo.css'** 47 | 48 | ## CSS Modules 49 | 50 | - 使用style module 51 | 52 | 在你的 ` 69 | ``` 70 | 71 | **详细原理查看官方文档[vue-loader](https://vue-loader.vuejs.org/zh/guide/css-modules.html#css-modules)** 72 | 73 | - 使用预处理器样 74 | 75 | 如果你的样式是从JavaScript中导入的,那么你只需要将把文件命名为`*.module.(less|scss|css)`。 76 | 77 | ```vue 78 | 85 | 86 | 94 | ``` 95 | -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@srejs/vue", 3 | "version": "1.4.2", 4 | "description": "@srejs/vue是一个轻量级服务端渲染骨架工具,为koa社区的nodejs开发框架提供具有服务端渲染能力的工具包,使得类似umajs类的web开发框架可以更方便实现前后端同构的服务端渲染能力。特点:轻量级,模板式调用页面进行服务端渲染,不限制后端路由。", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "files": [ 10 | "bin", 11 | "lib", 12 | "index.d.ts" 13 | ], 14 | "keywords": [ 15 | "ssr", 16 | "vue", 17 | "@umajs/plugin-vue-ssr", 18 | "umajs-vue-ssr", 19 | "@srejs", 20 | "nuxtjs", 21 | "vuessr" 22 | ], 23 | "bin": { 24 | "ssr": "./bin/index.js", 25 | "sre": "./bin/index.js", 26 | "srejs": "./bin/index.js" 27 | }, 28 | "scripts": { 29 | "build": "babel src --out-dir lib --copy-files", 30 | "start": "babel src --watch --out-dir lib --source-maps inline --copy-files", 31 | "watch": "babel src --watch --out-dir lib --source-maps inline --copy-files", 32 | "prepublish": "npm run build" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "git@github.com:dazjean/srejs.git" 37 | }, 38 | "publishConfig": { 39 | "registry": "https://registry.npmjs.org", 40 | "access": "public" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/dazjean/srejs/issues" 44 | }, 45 | "homepage": "https://github.com/dazjean/srejs#readme", 46 | "license": "MIT", 47 | "dependencies": { 48 | "@srejs/common": "^1.4.0", 49 | "@srejs/vue-webpack": "^1.4.0", 50 | "etag": "^1.8.1", 51 | "fresh": "^0.5.2", 52 | "koa-send": "^5.0.0", 53 | "serialize-javascript": "^3.1.0", 54 | "vue-server-renderer": "^2.6.14" 55 | }, 56 | "devDependencies": { 57 | "@babel/cli": "^7.22.10", 58 | "@babel/core": "^7.22.10", 59 | "@babel/plugin-transform-modules-commonjs": "^7.14.5", 60 | "@babel/plugin-transform-runtime": "^7.22.10", 61 | "@babel/preset-env": "^7.22.10" 62 | }, 63 | "gitHead": "da596c6a49044e00ebdbb45cb25841e2fbeb3b83" 64 | } 65 | -------------------------------------------------------------------------------- /packages/app/web/pages/router/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | //引入样式文件 3 | import './index.scss'; 4 | //引入组件 5 | import React, { Component } from 'react'; 6 | import { Route, Link, Switch, Redirect } from 'react-router-dom'; 7 | class Home extends Component { 8 | constructor(props) { 9 | super(props); 10 | this.goAboutPage = this.goAboutPage.bind(this); 11 | } 12 | goAboutPage() { 13 | this.props.history.push({ 14 | pathname: '/about', 15 | state: { 16 | msg: '来自首页的问候!by state' 17 | } 18 | }); 19 | } 20 | render() { 21 | return ( 22 |
23 | 我是首页路由 24 |
25 | 子页面1 26 |
27 | 子页面2 28 |
子页面3
29 |
30 | ); 31 | } 32 | } 33 | 34 | class About extends Component { 35 | constructor(props) { 36 | super(props); 37 | } 38 | render() { 39 | console.log(this.props.location); 40 | return ( 41 |
42 | 我是一个路由跳转后的子页面 43 |
44 |
参数:{JSON.stringify(this.props.location)}
45 | 回首页 46 |
47 | ); 48 | } 49 | } 50 | 51 | export default class APP extends Component { 52 | render() { 53 | return ( 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /example/uma-css-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.2", 4 | "description": "umajs-react-ssr", 5 | "author": "dazjean", 6 | "license": "ISC", 7 | "directories": { 8 | "lib": "lib", 9 | "test": "__tests__" 10 | }, 11 | "files": [ 12 | "lib", 13 | "index.d.ts" 14 | ], 15 | "publishConfig": { 16 | "registry": "https://registry.npmjs.org" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Umajs/Uma.git" 21 | }, 22 | "scripts": { 23 | "fix:src": "npx eslint src --fix --ext .ts", 24 | "fix:web": "npx eslint web --fix --ext .tsx", 25 | "start": "ts-node-dev --respawn src/app.ts", 26 | "build": "tsc && srejs build", 27 | "fix": "npm run fix:src && npm run fix:web", 28 | "postinstall": "npm run fix && npm run build", 29 | "preprod": "npm run build", 30 | "prod": "node app/app.js --production" 31 | }, 32 | "dependencies": { 33 | "@umajs/core": "^1.2.1", 34 | "@umajs/plugin-react-ssr": "^1.0.5", 35 | "@umajs/router": "^1.2.2", 36 | "koa": "^2.11.0", 37 | "react": "^17.0.2", 38 | "react-dom": "^17.0.2", 39 | "react-router-dom": "^5.2.0" 40 | }, 41 | "devDependencies": { 42 | "@types/koa": "^2.0.48", 43 | "@types/react": "^17.0.5", 44 | "@types/react-dom": "^17.0.4", 45 | "@types/react-router-dom": "^5.1.7", 46 | "@typescript-eslint/eslint-plugin": "^4.22.1", 47 | "@typescript-eslint/parser": "^4.22.1", 48 | "eslint": "^7.26.0", 49 | "eslint-config-airbnb-base": "^14.2.0", 50 | "eslint-plugin-import": "^2.22.1", 51 | "eslint-plugin-prettier": "^3.4.0", 52 | "eslint-plugin-react": "^7.23.2", 53 | "eslint-plugin-react-hooks": "^4.2.0", 54 | "eslint-plugin-typescript": "^0.14.0", 55 | "npm-run-all": "^4.1.5", 56 | "prettier": "^2.3.0", 57 | "ts-node": "^8.2.0", 58 | "ts-node-dev": "^1.0.0-pre.32", 59 | "typescript": "^3.2.2" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/app/web/pages/router/index.scss: -------------------------------------------------------------------------------- 1 | //sass style 2 | //------------------------------- 3 | @use "sass:math"; 4 | 5 | $baseFontSize: 32px !default; 6 | 7 | 8 | // pixels to rems 9 | @function pxToRem($px) { 10 | @return math.div($px, $baseFontSize) * 1rem; 11 | } 12 | body, 13 | div, 14 | dl, 15 | dt, 16 | dd, 17 | ul, 18 | ol, 19 | li, 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | h5, 25 | h6, 26 | pre, 27 | form, 28 | fieldset, 29 | input, 30 | textarea, 31 | p, 32 | blockquote, 33 | th, 34 | td, 35 | header, 36 | img 37 | { 38 | margin: 0; 39 | padding: 0; 40 | font-family: '微软雅黑'; 41 | } 42 | .clearfix:after { 43 | content: "."; 44 | display: block; 45 | height: 0; 46 | clear: both; 47 | visibility: hidden; 48 | } 49 | a{ 50 | text-decoration: none; 51 | } 52 | img{ 53 | display: block; 54 | } 55 | input{ 56 | border: none; 57 | outline: none; 58 | } 59 | li{ 60 | list-style: none; 61 | } 62 | html,body,#app{ 63 | font-size: 16px; 64 | width: 100%; 65 | height: 100%; 66 | overflow-y: auto; 67 | } 68 | *{ 69 | -webkit-tap-highlight-color:transparent; 70 | -webkit-overflow-scrolling:touch; 71 | } 72 | 73 | .demo{ 74 | width: 100%; 75 | height: 100%; 76 | margin: 0 auto; /*水平居中*/ 77 | position: relative; 78 | top: 50%; /*偏移*/ 79 | transform: translateY(-50%); 80 | // background-image: url('images/srejs.png'); 81 | background-size: auto; 82 | background-position-y: pxToRem(70px); 83 | font-weight: bold; 84 | font-size: $baseFontSize; 85 | text-align: center; 86 | // color: #ffffff; 87 | li a{ 88 | color:#03a9f4; 89 | } 90 | .title,.footer{ 91 | color: white; 92 | font-size: pxToRem(24px); 93 | } 94 | .footer{ 95 | text-align: center; 96 | a{ 97 | color: #ffffff !important; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /packages/vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@srejs/vue3", 3 | "version": "1.4.1", 4 | "description": "@srejs/vue是一个轻量级服务端渲染骨架工具,为koa社区的nodejs开发框架提供具有服务端渲染能力的工具包,使得类似umajs类的web开发框架可以更方便实现前后端同构的服务端渲染能力。特点:轻量级,模板式调用页面进行服务端渲染,不限制后端路由。", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "files": [ 10 | "bin", 11 | "lib", 12 | "index.d.ts" 13 | ], 14 | "keywords": [ 15 | "ssr", 16 | "vue", 17 | "vue3.0", 18 | "@umajs/plugin-vue-ssr", 19 | "umajs-vue-ssr", 20 | "umajs-vue3-ssr", 21 | "@srejs", 22 | "nuxtjs", 23 | "vue ssr" 24 | ], 25 | "bin": { 26 | "ssr": "./bin/index.js", 27 | "sre": "./bin/index.js", 28 | "srejs": "./bin/index.js" 29 | }, 30 | "scripts": { 31 | "link": "yarn link vue", 32 | "build": "babel src --out-dir lib --copy-files", 33 | "start": "babel src --watch --out-dir lib --source-maps inline --copy-files", 34 | "watch": "babel src --watch --out-dir lib --source-maps inline --copy-files", 35 | "prepublish": "npm run build" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git@github.com:dazjean/srejs.git" 40 | }, 41 | "publishConfig": { 42 | "registry": "https://registry.npmjs.org", 43 | "access": "public" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/dazjean/srejs/issues" 47 | }, 48 | "homepage": "https://github.com/dazjean/srejs#readme", 49 | "license": "MIT", 50 | "dependencies": { 51 | "@srejs/common": "^1.4.0", 52 | "@srejs/vue3-webpack": "^1.4.0", 53 | "@vue/server-renderer": "3.2.19", 54 | "etag": "^1.8.1", 55 | "fresh": "^0.5.2", 56 | "koa-send": "^5.0.0", 57 | "serialize-javascript": "^3.1.0" 58 | }, 59 | "devDependencies": { 60 | "@babel/cli": "^7.22.10", 61 | "@babel/core": "^7.22.10", 62 | "@babel/plugin-transform-modules-commonjs": "^7.14.5", 63 | "@babel/plugin-transform-runtime": "^7.22.10", 64 | "@babel/preset-env": "^7.22.10" 65 | }, 66 | "gitHead": "da596c6a49044e00ebdbb45cb25841e2fbeb3b83" 67 | } 68 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@srejs/react", 3 | "version": "1.4.0", 4 | "description": "@srejs/react是一个轻量级服务端渲染骨架工具,为koa社区的nodejs开发框架提供具有服务端渲染能力的工具包,使得类似umajs类的web开发框架可以更方便实现前后端同构的服务端渲染能力。特点:轻量级,模板式调用页面进行服务端渲染,不限制后端路由。", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "files": [ 10 | "bin", 11 | "lib", 12 | "index.d.ts" 13 | ], 14 | "keywords": [ 15 | "ssr", 16 | "react", 17 | "react-ssr", 18 | "@umajs/plugin-react-ssr", 19 | "umajs-react-ssr", 20 | "@srejs", 21 | "nextjs" 22 | ], 23 | "bin": { 24 | "ssr": "./bin/index.js", 25 | "sre": "./bin/index.js", 26 | "srejs": "./bin/index.js" 27 | }, 28 | "scripts": { 29 | "build": "babel src --out-dir lib --copy-files", 30 | "start": "babel src --watch --out-dir lib --source-maps inline --copy-files", 31 | "watch": "babel src --watch --out-dir lib --source-maps inline --copy-files", 32 | "prepublish": "npm run build" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "git@github.com:dazjean/srejs.git" 37 | }, 38 | "publishConfig": { 39 | "registry": "https://registry.npmjs.org", 40 | "access": "public" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/dazjean/srejs/issues" 44 | }, 45 | "homepage": "https://github.com/dazjean/srejs#readme", 46 | "license": "MIT", 47 | "dependencies": { 48 | "@srejs/common": "^1.4.0", 49 | "@srejs/react-webpack": "^1.4.0", 50 | "etag": "^1.8.1", 51 | "fresh": "^0.5.2", 52 | "koa-send": "^5.0.0", 53 | "react": "^17.0.2", 54 | "react-dom": "^17.0.2", 55 | "react-router-dom": "^5.2.0", 56 | "serialize-javascript": "^6.0.0" 57 | }, 58 | "devDependencies": { 59 | "@babel/cli": "^7.22.10", 60 | "@babel/core": "^7.22.10", 61 | "@babel/plugin-transform-modules-commonjs": "^7.14.5", 62 | "@babel/plugin-transform-runtime": "^7.22.10", 63 | "@babel/preset-env": "^7.22.10", 64 | "@babel/preset-react": "^7.7.4" 65 | }, 66 | "gitHead": "da596c6a49044e00ebdbb45cb25841e2fbeb3b83" 67 | } 68 | -------------------------------------------------------------------------------- /packages/app-vue/app.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa'; 2 | import srejs from '@srejs/vue'; 3 | const app = new Koa(); 4 | const Sre = new srejs(app, process.env.NODE_ENV != 'production', false, {}); 5 | app.use(async (ctx, next) => { 6 | if (ctx.path === '/vue' || ctx.path === '/') { 7 | const html = await Sre.render( 8 | ctx, 9 | 'vue', 10 | { 11 | title: 'vue ssr', 12 | keywords: 'srejs vue ssr', 13 | description: '简单好用的服务端渲染引擎工具!', 14 | state: { 15 | msg: 'vuex state' 16 | } 17 | }, 18 | { ssr: true } 19 | ); 20 | ctx.type = 'text/html'; 21 | ctx.body = html; 22 | } else if (ctx.path.startsWith('/index')) { 23 | const html = await Sre.render( 24 | ctx, 25 | 'index', 26 | { 27 | title: 'Vue-router', 28 | keywords: 'srejs vue ssr', 29 | description: '简单好用的服务端渲染引擎工具!', 30 | home: '这是home页', 31 | about: '这是about页' 32 | }, 33 | { ssr: true } 34 | ); 35 | ctx.type = 'text/html'; 36 | ctx.body = html; 37 | } else if (ctx.path.startsWith('/vuex')) { 38 | const html = await Sre.render( 39 | ctx, 40 | 'vuex', 41 | { 42 | title: '简单的计数器', 43 | keywords: 'vuessr vuex server', 44 | description: '简单的计数器 server', 45 | message: '这是来自服务端初始化数据', 46 | state: { 47 | count: 200 48 | } 49 | }, 50 | { ssr: true } 51 | ); 52 | ctx.type = 'text/html'; 53 | ctx.body = html; 54 | } else { 55 | await next(); 56 | ctx.type = 'text/html'; 57 | ctx.body = '404 not found'; 58 | } 59 | }); 60 | app.listen(8001); 61 | console.log('8001端口启动成功!'); 62 | -------------------------------------------------------------------------------- /packages/app-vue3/app.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa'; 2 | import srejs from '@srejs/vue3'; 3 | 4 | const app = new Koa(); 5 | const Sre = new srejs(app, process.env.NODE_ENV != 'production', false, { version: '3' }); 6 | app.use(async (ctx, next) => { 7 | if (ctx.path === '/vue' || ctx.path === '/') { 8 | const html = await Sre.render( 9 | ctx, 10 | 'vue', 11 | { 12 | title: 'vue ssr', 13 | keywords: 'srejs vue ssr', 14 | description: '简单好用的服务端渲染引擎工具!', 15 | state: { 16 | msg: 'vuex state', 17 | say: 'vuex 你好 vue ssr!' 18 | } 19 | }, 20 | { ssr: true } 21 | ); 22 | ctx.type = 'text/html'; 23 | ctx.body = html; 24 | } else if (ctx.path.startsWith('/index')) { 25 | const html = await Sre.render( 26 | ctx, 27 | 'index', 28 | { 29 | title: 'Vue-Router', 30 | keywords: 'srejs vue ssr', 31 | description: '简单好用的服务端渲染引擎工具!', 32 | home: '这是home页', 33 | about: '这是about页' 34 | }, 35 | { ssr: true } 36 | ); 37 | ctx.type = 'text/html'; 38 | ctx.body = html; 39 | } else if (ctx.path.startsWith('/vuex')) { 40 | const html = await Sre.render( 41 | ctx, 42 | 'vuex', 43 | { 44 | title: '简单的计数器', 45 | keywords: 'vuessr vuex server', 46 | description: '简单的计数器 server', 47 | message: '这是来自服务端初始化数据', 48 | state: { 49 | count: 200 50 | } 51 | }, 52 | { ssr: true } 53 | ); 54 | ctx.type = 'text/html'; 55 | ctx.body = html; 56 | } else { 57 | await next(); 58 | ctx.type = 'text/html'; 59 | ctx.body = '404 not found'; 60 | } 61 | }); 62 | app.listen(8001); 63 | console.log('8001端口启动成功!'); 64 | -------------------------------------------------------------------------------- /packages/vue-webpack/src/vue/hot.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import * as fs from 'fs'; 3 | import { devMiddleware, hotMiddleware } from 'koa-webpack-middleware'; 4 | import { getDevConfig } from './dev'; 5 | export let DevMiddlewareFileSystem = fs; 6 | 7 | export class Hotwebpack { 8 | constructor(app, page = true) { 9 | this.app = app; 10 | this.webpackConfig = getDevConfig(page, false, true); 11 | this.complier = webpack(this.webpackConfig); 12 | this.webpackDevMiddleware(); 13 | this.webpackHotMiddleware(); 14 | } 15 | webpackHotMiddleware() { 16 | const hotPath = '/__webpack_hmr'; 17 | let _hotMiddleware = hotMiddleware(this.complier, { 18 | path: hotPath, 19 | log: console.warn, 20 | heartbeat: 2000 21 | }); 22 | // 中间件过滤非 /__webpack_hmr路由 23 | this.app.use(function (ctx, next) { 24 | if (ctx.url !== hotPath) { 25 | return next(); 26 | } else { 27 | _hotMiddleware(ctx, next); 28 | } 29 | }); 30 | } 31 | webpackDevMiddleware() { 32 | let _devMiddleware = devMiddleware(this.complier, { 33 | serverSideRender: false, 34 | publicPath: '/', 35 | noInfo: true, 36 | quiet: true, 37 | index: false //不响应根路径请求 避免和页面组件路由冲突 38 | }); 39 | DevMiddlewareFileSystem = _devMiddleware.fileSystem; 40 | // 中间件过滤 非静态资源目录访问 .html,.js,.css,.png,jpeg,.svg,.jpg,.ttf 41 | this.app.use(function (ctx, next) { 42 | const filename = _devMiddleware.getFilenameFromUrl(ctx.url); 43 | if (filename === false) return next(); 44 | try { 45 | var stat = DevMiddlewareFileSystem.statSync(filename); 46 | if (!stat.isFile()) { 47 | return next(); 48 | } 49 | _devMiddleware(ctx, next); 50 | } catch (_e) { 51 | return next(); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/vue3-webpack/src/vue/hot.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import * as fs from 'fs'; 3 | import { devMiddleware, hotMiddleware } from 'koa-webpack-middleware'; 4 | import { getDevConfig } from './dev'; 5 | export let DevMiddlewareFileSystem = fs; 6 | 7 | export class Hotwebpack { 8 | constructor(app, page = true) { 9 | this.app = app; 10 | this.webpackConfig = getDevConfig(page, false, true); 11 | this.complier = webpack(this.webpackConfig); 12 | this.webpackDevMiddleware(); 13 | this.webpackHotMiddleware(); 14 | } 15 | webpackHotMiddleware() { 16 | const hotPath = '/__webpack_hmr'; 17 | let _hotMiddleware = hotMiddleware(this.complier, { 18 | path: hotPath, 19 | log: console.warn, 20 | heartbeat: 2000 21 | }); 22 | // 中间件过滤非 /__webpack_hmr路由 23 | this.app.use(function (ctx, next) { 24 | if (ctx.url !== hotPath) { 25 | return next(); 26 | } else { 27 | _hotMiddleware(ctx, next); 28 | } 29 | }); 30 | } 31 | webpackDevMiddleware() { 32 | let _devMiddleware = devMiddleware(this.complier, { 33 | serverSideRender: false, 34 | publicPath: '/', 35 | noInfo: true, 36 | quiet: true, 37 | index: false //不响应根路径请求 避免和页面组件路由冲突 38 | }); 39 | DevMiddlewareFileSystem = _devMiddleware.fileSystem; 40 | // 中间件过滤 非静态资源目录访问 .html,.js,.css,.png,jpeg,.svg,.jpg,.ttf 41 | this.app.use(function (ctx, next) { 42 | const filename = _devMiddleware.getFilenameFromUrl(ctx.url); 43 | if (filename === false) return next(); 44 | try { 45 | var stat = DevMiddlewareFileSystem.statSync(filename); 46 | if (!stat.isFile()) { 47 | return next(); 48 | } 49 | _devMiddleware(ctx, next); 50 | } catch (_e) { 51 | return next(); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/react-webpack/src/react/hot.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import * as fs from 'fs'; 3 | import { devMiddleware, hotMiddleware } from 'koa-webpack-middleware'; 4 | import { getDevConfig } from './dev'; 5 | export let DevMiddlewareFileSystem = fs; 6 | 7 | export class Hotwebpack { 8 | constructor(app, page = true) { 9 | this.app = app; 10 | this.webpackConfig = getDevConfig(page, false, true); 11 | this.complier = webpack(this.webpackConfig); 12 | this.webpackDevMiddleware(); 13 | this.webpackHotMiddleware(); 14 | } 15 | webpackHotMiddleware() { 16 | const hotPath = '/__webpack_hmr'; 17 | let _hotMiddleware = hotMiddleware(this.complier, { 18 | path: hotPath, 19 | log: console.warn, 20 | heartbeat: 2000 21 | }); 22 | // 中间件过滤非 /__webpack_hmr路由 23 | this.app.use(function (ctx, next) { 24 | if (ctx.url !== hotPath) { 25 | return next(); 26 | } else { 27 | _hotMiddleware(ctx, next); 28 | } 29 | }); 30 | } 31 | webpackDevMiddleware() { 32 | let _devMiddleware = devMiddleware(this.complier, { 33 | serverSideRender: false, 34 | publicPath: '/', 35 | noInfo: true, 36 | quiet: true, 37 | index: false //不响应根路径请求 避免和页面组件路由冲突 38 | }); 39 | DevMiddlewareFileSystem = _devMiddleware.fileSystem; 40 | // 中间件过滤 非静态资源目录访问 .html,.js,.css,.png,jpeg,.svg,.jpg,.ttf 41 | this.app.use(function (ctx, next) { 42 | const filename = _devMiddleware.getFilenameFromUrl(ctx.url); 43 | if (filename === false) return next(); 44 | try { 45 | var stat = DevMiddlewareFileSystem.statSync(filename); 46 | if (!stat.isFile()) { 47 | return next(); 48 | } 49 | _devMiddleware(ctx, next); 50 | } catch (_e) { 51 | return next(); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example/uma-useContext-useReducer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.2", 4 | "description": "umajs-react-ssr", 5 | "author": "dazjean", 6 | "license": "ISC", 7 | "directories": { 8 | "lib": "lib", 9 | "test": "__tests__" 10 | }, 11 | "files": [ 12 | "lib", 13 | "index.d.ts" 14 | ], 15 | "publishConfig": { 16 | "registry": "https://registry.npmjs.org" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Umajs/Uma.git" 21 | }, 22 | "scripts": { 23 | "fix:src": "npx eslint src --fix --ext .ts", 24 | "fix:web": "npx eslint web --fix --ext .tsx", 25 | "start": "ts-node-dev --respawn src/app.ts", 26 | "build": "tsc && srejs build", 27 | "fix": "npm run fix:src && npm run fix:web", 28 | "postinstall": "npm run fix && npm run build", 29 | "preprod": "npm run build", 30 | "prod": "node app/app.js --production" 31 | }, 32 | "dependencies": { 33 | "@umajs/core": "^1.2.1", 34 | "@umajs/plugin-react-ssr": "^1.0.5", 35 | "@umajs/plugin-views": "^2.0.1-alpha.0", 36 | "@umajs/router": "^1.2.2", 37 | "koa": "^2.11.0", 38 | "nunjucks": "^3.2.3", 39 | "react": "^17.0.2", 40 | "react-dom": "^17.0.2", 41 | "react-id-swiper": "^4.0.0", 42 | "react-router-dom": "^5.2.0", 43 | "swiper": "^6.6.1" 44 | }, 45 | "devDependencies": { 46 | "@types/koa": "^2.0.48", 47 | "@types/react": "^17.0.5", 48 | "@types/react-dom": "^17.0.4", 49 | "@types/react-router-dom": "^5.1.7", 50 | "@typescript-eslint/eslint-plugin": "^4.22.1", 51 | "@typescript-eslint/parser": "^4.22.1", 52 | "eslint": "^7.26.0", 53 | "eslint-config-airbnb-base": "^14.2.0", 54 | "eslint-plugin-import": "^2.22.1", 55 | "eslint-plugin-prettier": "^3.4.0", 56 | "eslint-plugin-react": "^7.23.2", 57 | "eslint-plugin-react-hooks": "^4.2.0", 58 | "eslint-plugin-typescript": "^0.14.0", 59 | "npm-run-all": "^4.1.5", 60 | "prettier": "^2.3.0", 61 | "ts-node": "^8.2.0", 62 | "ts-node-dev": "^1.0.0-pre.32", 63 | "typescript": "^3.2.2" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/uma-react-redux/web/pages/index/features/counter/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useSelector, useDispatch } from 'react-redux'; 3 | import { 4 | decrement, 5 | increment, 6 | incrementByAmount, 7 | incrementAsync, 8 | incrementIfOdd, 9 | selectCount, 10 | setIncrementAmount 11 | } from './counterSlice'; 12 | import styles from './Counter.module.css'; 13 | 14 | export function Counter() { 15 | const count = useSelector(selectCount); 16 | const incrementAmount = useSelector(setIncrementAmount); 17 | 18 | const dispatch = useDispatch(); 19 | 20 | const incrementValue = Number(incrementAmount) || 0; 21 | 22 | return ( 23 |
24 |
25 | 32 | {count} 33 | 40 |
41 |
42 | setIncrementAmount(e.target.value)} 47 | /> 48 | 54 | 60 | 66 |
67 |
68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /packages/app/web/pages/index/index.tsx: -------------------------------------------------------------------------------- 1 | import './index.scss'; 2 | import React from 'react'; 3 | import srejsLogo from '@/images/srejs.png'; 4 | const commonjsLogo = require('@/images/srejs.png').default; 5 | import { testTreeSharkingA } from './fool'; 6 | type typeProps = { 7 | title: string; 8 | userTitle: string; 9 | }; 10 | const Index = (props: typeProps) => { 11 | const { title, userTitle } = props; 12 | testTreeSharkingA(); 13 | return ( 14 |
15 |
16 |
17 |

18 | {title} 19 | {userTitle} 20 |

21 | 41 |

42 | https://github.com/dazjean/srejs 43 |

44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | ); 52 | }; 53 | 54 | function timeout() { 55 | return new Promise((reslove) => { 56 | setTimeout(() => { 57 | reslove({ 58 | userTitle: '列表' 59 | }); 60 | }, 500); 61 | }); 62 | } 63 | 64 | Index.getInitialProps = async () => { 65 | return await timeout(); 66 | }; 67 | export default Index; 68 | -------------------------------------------------------------------------------- /doc/react/page-router.md: -------------------------------------------------------------------------------- 1 | # 页面组件 2 | > `rootDir`默认为根目录下`src`文件夹下创建pages目录。eg:src/pages/index/index.js;在服务端使用时`index`作为页面组件标识。 3 | 4 | 5 | - 普通页面组件 6 | ```js 7 | export default class App extends Component { 8 | constructor(props) { 9 | super(props); 10 | } 11 | render() { 12 | return ( 13 |
14 | hello srejs 15 |
16 | ); 17 | } 18 | } 19 | 20 | ``` 21 | 22 | 服务端路由 23 | 24 | ```js 25 | import Koa from 'koa'; 26 | import srejs from '@srejs/react'; 27 | const app = new Koa(); 28 | const Sre = new srejs(app,process.env.NODE_ENV != 'production',false); 29 | app.use(async (ctx,next)=>{ 30 | if(ctx.path==="/"){ 31 | const html = await Sre.render(ctx,'index',{title:'介绍'}); 32 | ctx.type = 'text/html'; 33 | ctx.body = html; 34 | }else{ 35 | await next(); 36 | } 37 | }) 38 | ``` 39 | 40 | - 使用react-router-dom 41 | > 项目如果使用路由,export导出组件为` `包裹的`` 42 | ```js 43 | export default class APP extends Component { 44 | render() { 45 | return ( 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | } 54 | } 55 | ``` 56 | 57 | 使用react-router-dom时服务端路由需要和客户端路由保持一致;默认baseName为页面组件名称 eg:`router`嵌套路由组件,默认`baseName`为`/router`。可通过运行期支持动态传递修改`baseName`值。 58 | 59 | ```js 60 | import Koa from 'koa'; 61 | import srejs from '@srejs/react'; 62 | const app = new Koa(); 63 | const Sre = new srejs(app,process.env.NODE_ENV != 'production',false); 64 | app.use(async (ctx,next)=>{ 65 | if(ctx.path.startsWith('/router')){ // 客户端默认basename为页面组件名称 eg:web/pages/router/index.tsx basename默认为:router 66 | const html = await Sre.render(ctx,'router'); 67 | ctx.type = 'text/html'; 68 | ctx.body = html; 69 | }else{ 70 | await next(); 71 | } 72 | }) 73 | ``` 74 | 75 | 76 | 77 | **说明** 框架默认不采用页面组件工程目录作为默认路由,建议采用服务端路由自由搭配使用。如果习惯采用文件路由则初始化srejs时第三个参数`defaultRouter`设置为true。 -------------------------------------------------------------------------------- /example/uma-react-redux/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: [ 4 | 'typescript', 5 | '@typescript-eslint', 6 | ], 7 | extends: ['airbnb-base'], 8 | rules: { 9 | // allow debugger during development 10 | 'linebreak-style': 0, 11 | 'indent': [2, 4, { 12 | 'SwitchCase': 1 13 | }], 14 | 'max-len': [2, { 'code': 160, 'ignoreUrls': true }], 15 | 'radix': ['error', 'as-needed'], 16 | 'object-shorthand': ['error', 'methods'], 17 | 'no-unused-expressions': ["error", { 18 | "allowShortCircuit": true 19 | }], 20 | 'no-bitwise': ['error', { 21 | 'allow': ['~'] 22 | }], 23 | 'import/no-unresolved': 0, 24 | 'import/prefer-default-export': 0, 25 | 'import/no-dynamic-require': 0, 26 | 'object-curly-newline': 0, 27 | 'consistent-return': 0, 28 | 'no-unused-vars': 0, 29 | 'no-useless-constructor': 0, 30 | 'no-empty-function': 0, 31 | 'class-methods-use-this': 0, 32 | 'import/no-extraneous-dependencies': 0, 33 | '@typescript-eslint/no-unused-vars': 2, 34 | '@typescript-eslint/no-useless-constructor': 2, 35 | 'no-restricted-syntax': 0, 36 | 'no-param-reassign': 0, 37 | 'no-return-await': 0, 38 | 'no-use-before-define': 0, 39 | 'no-await-in-loop': 0, 40 | 'no-continue': 0, 41 | 'no-plusplus': 0, 42 | 'no-debugger': 0, 43 | 'no-console': 0, 44 | 'no-bitwise': 0, 45 | "padding-line-between-statements": [ 46 | "warn", 47 | { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" }, 48 | { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"] }, 49 | { "blankLine": "always", "prev": "*", "next": "return" }, 50 | { "blankLine": "always", "prev": "block-like", "next": "*" }, 51 | { "blankLine": "always", "prev": "block", "next": "*" }, 52 | { "blankLine": "always", "prev": "function", "next": "*" }, 53 | ], 54 | } 55 | } 56 | --------------------------------------------------------------------------------