Skip to content

Commit 653038b

Browse files
author
haili.lhq
committed
feat: support docs custom index.ejs index.tsx
1 parent 1549fa8 commit 653038b

4 files changed

Lines changed: 193 additions & 168 deletions

File tree

src/built-in-plugins/command-docs/plugin/dev-docs.ts

Lines changed: 111 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,20 @@ import { tempPath, docsPath } from '../../../utils/structor-config';
1111
import { runWebpackDevServer } from '../../../utils/webpack-dev-server';
1212

1313
export async function devDocs() {
14-
const docsEntryPath = path.join(pri.projectRootPath, tempPath.dir, 'docs-entry.tsx');
15-
prepare(docsEntryPath);
14+
const currentSelectedSourceType = pri.selectedSourceType;
15+
const targetRoot =
16+
currentSelectedSourceType === 'root'
17+
? pri.projectRootPath
18+
: pri.packages.find(p => p.name === currentSelectedSourceType).rootPath;
19+
20+
// 自定义模板
21+
const customHTML = path.join(targetRoot, docsPath.dir, 'index.ejs');
22+
const customIndex = path.join(targetRoot, docsPath.dir, 'index.tsx');
23+
const isExistCustomIndex = fs.existsSync(customIndex);
24+
const docsEntryPath = isExistCustomIndex
25+
? customIndex
26+
: path.join(pri.projectRootPath, tempPath.dir, 'docs-entry.tsx');
27+
prepare(docsEntryPath, !isExistCustomIndex);
1628

1729
await pri.project.ensureProjectFiles();
1830
await pri.project.checkProjectFiles();
@@ -48,7 +60,7 @@ export async function devDocs() {
4860
devUrl: pri.sourceConfig.host,
4961
entryPath: docsEntryPath,
5062
devServerPort: freePort,
51-
htmlTemplatePath: path.join(__dirname, '../../../../template-project.ejs'),
63+
htmlTemplatePath: fs.existsSync(customHTML) ? customHTML : path.join(__dirname, '../../../../template-project.ejs'),
5264
htmlTemplateArgs: {
5365
appendHead: `
5466
<style>
@@ -64,7 +76,7 @@ export async function devDocs() {
6476
});
6577
}
6678

67-
function prepare(docsEntryPath: string) {
79+
function prepare(docsEntryPath: string, generateEntry: boolean) {
6880
pri.build.pipeSassLoaderOptions(options => {
6981
return {
7082
...options,
@@ -96,97 +108,99 @@ function prepare(docsEntryPath: string) {
96108
return paths;
97109
});
98110

99-
pri.project.onAnalyseProject(files => {
100-
const result = {
101-
projectAnalyseDocs: {
102-
docs: files
103-
.filter(file => {
104-
if (!path.format(file).startsWith(path.join(pri.sourceRoot, docsPath.dir))) {
105-
return false;
106-
}
107-
108-
if (file.isDir) {
109-
return false;
110-
}
111-
112-
if (['.tsx'].indexOf(file.ext) === -1) {
113-
return false;
114-
}
115-
116-
return true;
117-
})
118-
.map(file => {
119-
return { file };
120-
}),
121-
},
122-
};
123-
124-
// Create entry file for docs
125-
const docList: string[] = [];
126-
127-
const docsEntryContent = prettier.format(
128-
`
129-
import * as React from "react"
130-
import * as ReactDOM from 'react-dom'
131-
import { hot } from "react-hot-loader/root"
132-
import { setConfig } from "react-hot-loader"
133-
134-
setConfig({
135-
ignoreSFC: true, // RHL will be __completely__ disabled for SFC
136-
pureRender: true, // RHL will not change render method
137-
})
138-
139-
const DocsWrapper = require("${path.join(__dirname, 'docs-wrapper')}").default
140-
141-
${(() => {
142-
const docFiles = result.projectAnalyseDocs.docs;
143-
return docFiles
144-
.map((docFile, index) => {
145-
const docFilePathWithoutPrefix = path.join(docFile.file.dir, docFile.file.name);
146-
const docImportPath = path.relative(path.parse(docsEntryPath).dir, docFilePathWithoutPrefix);
147-
const fileName = `Doc${index}`;
148-
docList.push(`
149-
{
150-
name: "${docFile.file.name}",
151-
element: ${fileName},
152-
text: ${fileName}Text
153-
}
154-
`);
155-
return `
156-
import * as ${fileName} from '${docImportPath}'
157-
const ${fileName}Text = require('-!raw-loader!${docImportPath}')
158-
`;
159-
})
160-
.join('\n');
161-
})()}
162-
163-
const DocComponents: any[] = [${docList.join(',')}]
164-
165-
const Docs = () => <DocsWrapper docs={DocComponents}/>
166-
167-
const ROOT_ID = '${pri.sourceConfig.projectRootId}';
168-
169-
setConfig({ pureSFC: true, pureRender: true })
170-
171-
const HotDocs = hot(Docs);
172-
173-
// Create entry div if not exist.
174-
if (!document.getElementById(ROOT_ID)) {
175-
const rootDiv = document.createElement('div');
176-
rootDiv.id = ROOT_ID;
177-
document.body.appendChild(rootDiv);
178-
}
179-
180-
ReactDOM.render(<HotDocs />, document.getElementById(ROOT_ID));
181-
`,
182-
{
183-
...prettierConfig,
184-
parser: 'typescript',
185-
},
186-
);
187-
188-
fs.outputFileSync(docsEntryPath, docsEntryContent);
189-
190-
return result;
191-
});
111+
if (generateEntry) {
112+
pri.project.onAnalyseProject(files => {
113+
const result = {
114+
projectAnalyseDocs: {
115+
docs: files
116+
.filter(file => {
117+
if (!path.format(file).startsWith(path.join(pri.sourceRoot, docsPath.dir))) {
118+
return false;
119+
}
120+
121+
if (file.isDir) {
122+
return false;
123+
}
124+
125+
if (['.tsx'].indexOf(file.ext) === -1) {
126+
return false;
127+
}
128+
129+
return true;
130+
})
131+
.map(file => {
132+
return { file };
133+
}),
134+
},
135+
};
136+
// Create entry file for docs
137+
const docList: string[] = [];
138+
139+
const docsEntryContent = prettier.format(
140+
`
141+
import * as React from "react"
142+
import * as ReactDOM from 'react-dom'
143+
import { hot } from "react-hot-loader/root"
144+
import { setConfig } from "react-hot-loader"
145+
146+
setConfig({
147+
ignoreSFC: true, // RHL will be __completely__ disabled for SFC
148+
pureRender: true, // RHL will not change render method
149+
})
150+
151+
const DocsWrapper = require("${path.join(__dirname, 'docs-wrapper')}").default
152+
153+
${(() => {
154+
const docFiles = result.projectAnalyseDocs.docs;
155+
return docFiles
156+
.map((docFile, index) => {
157+
const docFilePathWithoutPrefix = path.join(docFile.file.dir, docFile.file.name);
158+
const docImportPath = path.relative(path.parse(docsEntryPath).dir, docFilePathWithoutPrefix);
159+
const fileName = `Doc${index}`;
160+
docList.push(`
161+
{
162+
name: "${docFile.file.name}",
163+
element: ${fileName},
164+
text: ${fileName}Text
165+
}
166+
`);
167+
return `
168+
import * as ${fileName} from '${docImportPath}'
169+
const ${fileName}Text = require('-!raw-loader!${docImportPath}')
170+
`;
171+
})
172+
.join('\n');
173+
})()}
174+
175+
const DocComponents: any[] = [${docList.join(',')}]
176+
window.DocComponents = DocComponents;
177+
178+
const Docs = () => <DocsWrapper docs={DocComponents}/>
179+
180+
const ROOT_ID = '${pri.sourceConfig.projectRootId}';
181+
182+
setConfig({ pureSFC: true, pureRender: true })
183+
184+
const HotDocs = hot(Docs);
185+
186+
// Create entry div if not exist.
187+
if (!document.getElementById(ROOT_ID)) {
188+
const rootDiv = document.createElement('div');
189+
rootDiv.id = ROOT_ID;
190+
document.body.appendChild(rootDiv);
191+
}
192+
193+
ReactDOM.render(<HotDocs />, document.getElementById(ROOT_ID));
194+
`,
195+
{
196+
...prettierConfig,
197+
parser: 'typescript',
198+
},
199+
);
200+
201+
fs.outputFileSync(docsEntryPath, docsEntryContent);
202+
203+
return result;
204+
});
205+
}
192206
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @author 紫益
3+
* @description 组件异常 Catch
4+
*/
5+
6+
import * as React from 'react';
7+
8+
interface State {
9+
error: Error;
10+
}
11+
12+
export class ErrorBoundary extends React.PureComponent<any, State> {
13+
static getDerivedStateFromError(error: Error) {
14+
return { error };
15+
}
16+
17+
public state: State = { error: undefined };
18+
19+
render() {
20+
if (this.state.error) {
21+
return <div>{this.state.error.message}</div>;
22+
}
23+
24+
return this.props.children;
25+
}
26+
}
27+
28+
export function withErrorBoundary(Elem: React.ComponentType): React.ComponentType {
29+
return props => (
30+
<ErrorBoundary>
31+
<Elem {...props} />
32+
</ErrorBoundary>
33+
);
34+
}

0 commit comments

Comments
 (0)