Skip to content

Commit 283d8e1

Browse files
committed
feat: add new store
1 parent cead790 commit 283d8e1

16 files changed

+289
-38
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pri",
3-
"version": "0.0.32",
3+
"version": "0.0.33",
44
"types": "src/index.ts",
55
"main": "built/index.js",
66
"scripts": {

src/commands/dev/dashboard/client/pages/main/main.component.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { RoutesComponent } from './routes/routes.component'
99
import { LayoutComponent } from './layout/layout.component'
1010
import { NotFoundComponent } from './not-found/not-found.component'
1111
import { ConfigComponent } from './config/config.component'
12+
import { StoresComponent } from './stores/stores.component'
1213

1314
@Connect
1415
export class MainComponent extends PureComponent<Props, State> {
@@ -27,6 +28,8 @@ export class MainComponent extends PureComponent<Props, State> {
2728
return <NotFoundComponent />
2829
case 'config':
2930
return <ConfigComponent />
31+
case 'stores':
32+
return <StoresComponent />
3033
default:
3134
return null
3235
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Connect } from "dob-react"
2+
import * as React from "react"
3+
import { Props, State } from './store.type'
4+
import * as S from './store.style'
5+
import { PureComponent } from '../../../utils/react-helper'
6+
7+
@Connect
8+
export class StoreComponent extends PureComponent<Props, State> {
9+
static defaultProps = new Props()
10+
state = new State()
11+
12+
render() {
13+
return (
14+
<S.Container>
15+
Stores TODO
16+
</S.Container>
17+
)
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styled from 'styled-components'
2+
3+
export const Container = styled.div`
4+
5+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class Props {
2+
3+
}
4+
5+
export class State {
6+
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Connect } from "dob-react"
2+
import * as React from "react"
3+
import { Props, State } from './stores.type'
4+
import * as S from './stores.style'
5+
import { PureComponent } from '../../../utils/react-helper'
6+
7+
@Connect
8+
export class StoresComponent extends PureComponent<Props, State> {
9+
static defaultProps = new Props()
10+
state = new State()
11+
12+
render() {
13+
return (
14+
<S.Container>
15+
Store TODO
16+
</S.Container>
17+
)
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styled from 'styled-components'
2+
3+
export const Container = styled.div`
4+
5+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class Props {
2+
3+
}
4+
5+
export class State {
6+
7+
}

src/commands/dev/dashboard/client/pages/menu/new-store/form.tsx

+19-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as React from "react"
33
import { Props, State } from './new-store.type'
44
import * as S from '../menu.style'
55
import { PureComponent } from '../../../utils/react-helper'
6-
import { Form, Button, Input } from 'antd'
6+
import { Form, Button, Input, Switch } from 'antd'
77

88
const FormItem = Form.Item
99

@@ -45,20 +45,32 @@ class FormComponent extends PureComponent<Props, State> {
4545
<Form onSubmit={this.handleSubmit}>
4646
<FormItem
4747
{...formItemLayout}
48-
label="Path"
48+
label="Name"
4949
>
50-
{this.props.form.getFieldDecorator('path', {
51-
initialValue: 'about',
50+
{this.props.form.getFieldDecorator('name', {
51+
initialValue: 'application',
5252
rules: [{
53-
type: 'string', message: 'Path must be string!',
53+
type: 'string', message: 'Name must be string!',
5454
}, {
55-
required: true, message: 'Path is required!',
55+
required: true, message: 'Name is required!',
5656
}],
5757
})(
5858
<Input />
5959
)}
6060
</FormItem>
6161

62+
<FormItem
63+
{...formItemLayout}
64+
label="With demo"
65+
>
66+
{this.props.form.getFieldDecorator('withDemo', {
67+
initialValue: true,
68+
valuePropName: "checked"
69+
})(
70+
<Switch />
71+
)}
72+
</FormItem>
73+
6274
<FormItem {...tailFormItemLayout}>
6375
<Button
6476
type="primary"
@@ -72,7 +84,7 @@ class FormComponent extends PureComponent<Props, State> {
7284

7385
private handleSubmit = async (e: any) => {
7486
e.preventDefault();
75-
await this.props.ApplicationAction.addPage(this.props.form.getFieldsValue())
87+
await this.props.ApplicationAction.addStore(this.props.form.getFieldsValue())
7688
this.props.onSuccess()
7789
}
7890
}

src/commands/dev/dashboard/client/pages/struct/struct.component.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,14 @@ export class StructComponent extends PureComponent<Props, State> {
106106
key: 'stores',
107107
title: `Stores (${this.props.ApplciationStore.status.info.stores.length})`,
108108
icon: <TreeIcon type="database" />,
109-
disabled: this.props.ApplciationStore.status.info.stores.length === 0
109+
disabled: this.props.ApplciationStore.status.info.stores.length === 0,
110+
children: this.props.ApplciationStore.status.info.stores.map(store => {
111+
return {
112+
key: 'store-' + store.filePath,
113+
title: store.name,
114+
icon: <TreeIcon type="database" />
115+
}
116+
})
110117
})
111118
}
112119

src/commands/dev/dashboard/client/stores/application.ts

+7
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ export class ApplicationAction {
5454
await this.fetch<typeof options>('addPage', options)
5555
}
5656

57+
@Action public async addStore(options: {
58+
name: string
59+
withDemo: boolean
60+
}) {
61+
await this.fetch<typeof options>('addStore', options)
62+
}
63+
5764
@Action public async createConfig() {
5865
await this.fetch('createConfig')
5966
}

src/commands/dev/dashboard/server/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ io.on('connection', async (socket) => {
8383
}
8484
})
8585

86+
socketListen('addStore', async (data, resolve, reject) => {
87+
try {
88+
await projectManage.addStore(projectRootPath, data)
89+
resolve()
90+
} catch (error) {
91+
reject(error)
92+
}
93+
})
94+
8695
socketListen('createLayout', async (data, resolve, reject) => {
8796
try {
8897
await projectManage.createLayout(projectRootPath)

src/utils/analyse-project-interface.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class IProjectInfo {
1414
public hasLayoutFile = false
1515
public has404File = false
1616
public stores: Array<{
17-
path: string
17+
filePath: string
18+
name: string
1819
}> = []
1920
}

src/utils/analyse-project.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,8 @@ function judgeStoreFile(projectRootPath: string, dir: string, fileStats: WalkSta
151151
return null
152152
}
153153

154-
const prefix = '/' + path.relative(STORE_ROOT, relativePath)
155-
156154
return {
157-
path: prefix
155+
filePath: path.join(dir, fileStats.name),
156+
name: fileInfo.name
158157
}
159158
}

src/utils/create-entry.ts

+75-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as prettier from "prettier"
44
import { IProjectInfo } from "./analyse-project-interface"
55
import { md5 } from "./md5"
66
import { IConfig } from "./project-config-interface"
7+
import * as _ from "lodash"
78

89
interface IEntryInfo {
910
pageImporter: string
@@ -13,17 +14,21 @@ interface IEntryInfo {
1314
notFoundRoute: string
1415
setEnv: string
1516
setCustomEnv: string
17+
storesImporter: string
18+
storesHelper: string
1619
}
1720

1821
// Entry file content
19-
const entryFileContent = (entryInfo: IEntryInfo, env: string) => `
22+
const getEntryContent = (entryInfo: IEntryInfo, info: IProjectInfo, env: string) => `
2023
import { setEnvLocal, setEnvProd, setCustomEnv } from "pri"
2124
import * as React from "react"
2225
import * as ReactDOM from "react-dom"
2326
import Loadable from "react-loadable"
2427
import { Redirect, Route, Switch, Router } from "react-router-dom"
2528
import createBrowserHistory from 'history/createBrowserHistory'
2629
30+
${entryInfo.storesImporter}
31+
2732
const customHistory = createBrowserHistory()
2833
2934
${entryInfo.setEnv}
@@ -50,12 +55,14 @@ const entryFileContent = (entryInfo: IEntryInfo, env: string) => `
5055
5156
public render() {
5257
return (
58+
${info.stores.length > 0 ? "<Provider {...stores}>" : ""}
5359
<Router history={customHistory}>
5460
<Switch>
5561
${entryInfo.pageRoutes}
5662
${entryInfo.notFoundRoute}
5763
</Switch>
5864
</Router>
65+
${info.stores.length > 0 ? "</Provider>" : ""}
5966
)
6067
}
6168
}
@@ -66,6 +73,15 @@ const entryFileContent = (entryInfo: IEntryInfo, env: string) => `
6673
)
6774
`
6875

76+
const getHelperContent = (entryInfo: IEntryInfo, info: IProjectInfo, env: string) => `
77+
/**
78+
* Do not edit this file.
79+
* This file is automatic generated to get type help.
80+
*/
81+
82+
${entryInfo.storesHelper}
83+
`
84+
6985
export async function createEntry(info: IProjectInfo, projectRootPath: string, env: string, config: IConfig) {
7086
const entryInfo: IEntryInfo = {
7187
pageImporter: "",
@@ -74,7 +90,9 @@ export async function createEntry(info: IProjectInfo, projectRootPath: string, e
7490
notFoundImporter: "",
7591
notFoundRoute: "",
7692
setEnv: "",
77-
setCustomEnv: ""
93+
setCustomEnv: "",
94+
storesImporter: "",
95+
storesHelper: ""
7896
}
7997

8098
// Set env
@@ -103,23 +121,61 @@ export async function createEntry(info: IProjectInfo, projectRootPath: string, e
103121

104122
if (info.routes.length < 2) {
105123
// If only one page, don't need code splitting.
106-
entryInfo.pageImporter += `
107-
import ${componentName} from "${path.join(pathInfo.dir, pathInfo.name)}"
108-
`
124+
if (info.stores.length === 0) {
125+
entryInfo.pageImporter += `
126+
import ${componentName} from "${path.join(pathInfo.dir, pathInfo.name)}"
127+
`
128+
} else {
129+
entryInfo.pageImporter += `
130+
import ${componentName}Temp from "${path.join(pathInfo.dir, pathInfo.name)}"
131+
${componentName} = Connect()(${componentName}Temp)
132+
`
133+
}
109134
} else {
135+
const importCode = info.stores.length === 0 ?
136+
`import("${path.join(pathInfo.dir, pathInfo.name)}")` :
137+
`import("${path.join(pathInfo.dir, pathInfo.name)}").then(res => Connect()(res.default)) `
138+
110139
entryInfo.pageImporter += `
111140
const ${componentName} = Loadable({
112-
loader: () => import("${path.join(pathInfo.dir, pathInfo.name)}"),
141+
loader: () => ${importCode},
113142
loading: () => null
114143
})\n
115144
`
116145
}
117146

118147
const routeComponent = info.layout ? "LayoutRoute" : "Route"
119148

120-
entryInfo.pageRoutes += `<${routeComponent} exact path="${route.path}" component={${componentName}} />\n`
149+
entryInfo.pageRoutes += `
150+
<${routeComponent} exact path="${route.path}" component={${componentName}} />\n
151+
`
121152
})
122153

154+
// Set stores
155+
const safeName = (str: string) => _.upperFirst(_.camelCase(str))
156+
if (info.stores.length > 0) {
157+
entryInfo.storesImporter += `import { useStrict } from "dob"\n`
158+
entryInfo.storesImporter += `import { Connect, Provider } from "dob-react"\n`
159+
entryInfo.storesImporter += `useStrict()\n`
160+
entryInfo.storesImporter += `import { stores } from "../src/helper"\n`
161+
entryInfo.storesHelper += `import { combineStores } from "dob"\n`
162+
entryInfo.storesHelper += info.stores
163+
.map(eachStore => {
164+
const filePath = path.parse(eachStore.filePath)
165+
const importAbsolutePath = path.join(filePath.dir, filePath.name)
166+
const importRelativePath = path.relative(path.join(projectRootPath, "src"), importAbsolutePath)
167+
return `import { ${safeName(eachStore.name)}Action, ${safeName(eachStore.name)}Store } from "./${importRelativePath}"`
168+
})
169+
.join("\n")
170+
entryInfo.storesHelper += `
171+
\nconst stores = combineStores({${info.stores.map(eachStore => {
172+
return `${safeName(eachStore.name)}Action, ${safeName(eachStore.name)}Store`
173+
}).join(',')}})
174+
175+
export { stores }
176+
`
177+
}
178+
123179
// Set layout
124180
if (info.layout) {
125181
const layoutPath = path.parse(info.layout.filePath)
@@ -149,10 +205,21 @@ export async function createEntry(info: IProjectInfo, projectRootPath: string, e
149205

150206
// Create entry tsx file
151207
const entryPath = path.join(projectRootPath, ".temp/entry.tsx")
152-
fs.outputFileSync(entryPath, prettier.format(entryFileContent(entryInfo, env), {
208+
fs.outputFileSync(entryPath, prettier.format(getEntryContent(entryInfo, info, env), {
153209
semi: false,
154210
parser: "typescript"
155211
}))
156212

213+
// If has stores, create helper.ts
214+
const helperPath = path.join(projectRootPath, "src/helper.ts")
215+
if (info.stores.length > 0) {
216+
fs.outputFileSync(helperPath, prettier.format(getHelperContent(entryInfo, info, env), {
217+
semi: false,
218+
parser: "typescript"
219+
}))
220+
} else {
221+
fs.removeSync(helperPath)
222+
}
223+
157224
return entryPath
158225
}

0 commit comments

Comments
 (0)