@bundlekit/plugin-react 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +17 -0
- package/package.json +32 -0
- package/templates/template-react-js/.bundlekitrc.js.ejs +24 -0
- package/templates/template-react-js/package.json.ejs +18 -0
- package/templates/template-react-js/public/index.html.ejs +11 -0
- package/templates/template-react-js/src/App.jsx.ejs +18 -0
- package/templates/template-react-js/src/entry-client.jsx.ejs +12 -0
- package/templates/template-react-js/src/entry-server.jsx.ejs +7 -0
- package/templates/template-react-js/src/index.jsx.ejs +27 -0
- package/templates/template-react-ts/.bundlekitrc.ts.ejs +47 -0
- package/templates/template-react-ts/mock/index.ts +27 -0
- package/templates/template-react-ts/package.json.ejs +22 -0
- package/templates/template-react-ts/public/index.html.ejs +11 -0
- package/templates/template-react-ts/src/App.tsx.ejs +18 -0
- package/templates/template-react-ts/src/entry-client.tsx.ejs +14 -0
- package/templates/template-react-ts/src/entry-server.tsx.ejs +13 -0
- package/templates/template-react-ts/src/index.tsx.ejs +27 -0
- package/templates/template-react-ts/tsconfig.json +24 -0
package/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IPluginAPIClass, IBuildConfig } from "@bundlekit/shared-utils";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
defaultModes: {
|
|
5
|
+
"plugin:react": "development" as const,
|
|
6
|
+
},
|
|
7
|
+
apply(api: IPluginAPIClass, options: IBuildConfig) {
|
|
8
|
+
const buildConfig = api.service.getBuildConfig();
|
|
9
|
+
if (!buildConfig) return;
|
|
10
|
+
|
|
11
|
+
for (const env of Object.keys(buildConfig.config || {})) {
|
|
12
|
+
buildConfig.config[env].framework = "react";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
api.modifyBuildConfig(buildConfig);
|
|
16
|
+
},
|
|
17
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bundlekit/plugin-react",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "React plugin for bundlekit - provides React build support and project templates",
|
|
5
|
+
"main": "./index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.ts",
|
|
9
|
+
"templates",
|
|
10
|
+
"package.json"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react",
|
|
14
|
+
"bundlekit-plugin",
|
|
15
|
+
"bundlekit"
|
|
16
|
+
],
|
|
17
|
+
"author": "harhao@163.com",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@bundlekit/shared-utils": "0.0.1"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"registry": "https://registry.npmjs.org/",
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">= 18.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"plugin:react:build": "echo 'plugin:react built successfully'"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
mode: "development",
|
|
3
|
+
bundler: "<%= bundler %>",
|
|
4
|
+
config: {
|
|
5
|
+
development: {
|
|
6
|
+
target: "web",
|
|
7
|
+
publicPath: "/",
|
|
8
|
+
entry: <% if (ssr) { %>"src/entry-client.jsx"<% } else { %>"src/index.jsx"<% } %>,
|
|
9
|
+
output: { dir: "dist", filename: "[name].js", formats: "umd" },
|
|
10
|
+
alias: { "@": "src" },
|
|
11
|
+
externals: [],
|
|
12
|
+
js: { sourcemap: true, minify: false, splitChunks: true },
|
|
13
|
+
devServer: { open: true, proxy: {}, https: false, host: "0.0.0.0", port: 3000 },<% if (ssr) { %>
|
|
14
|
+
ssr: {
|
|
15
|
+
entry: "src/entry-server.jsx",
|
|
16
|
+
output: { dir: "dist/server", filename: "server.cjs", formats: "commonjs" },
|
|
17
|
+
externals: "auto",
|
|
18
|
+
template: "public/index.html",
|
|
19
|
+
placeholder: "<!--ssr-outlet-->",
|
|
20
|
+
dev: true,
|
|
21
|
+
},<% } %>
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= projectName %>",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "<%= description %>",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"clean": "rimraf dist",
|
|
7
|
+
"dev": "bundlekit-service serve --bundler <%= bundler %> --mode development",
|
|
8
|
+
"build": "bundlekit-service build --bundler <%= bundler %> --mode production"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"react": "^18.2.0",
|
|
12
|
+
"react-dom": "^18.2.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@bundlekit/service": "workspace:^",
|
|
16
|
+
"@bundlekit/plugin-react": "workspace:^"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= projectName %></title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"><!--ssr-outlet--></div>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
function App() {
|
|
4
|
+
const [count, setCount] = useState(0);
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<div>
|
|
8
|
+
<h1>
|
|
9
|
+
<span>Hello, <%= projectName %>!</span>
|
|
10
|
+
<button onClick={() => setCount(count + 1)}>
|
|
11
|
+
Clicked {count} times
|
|
12
|
+
</button>
|
|
13
|
+
</h1>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default App;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { hydrateRoot, createRoot } from "react-dom/client";
|
|
3
|
+
import App from "./App";
|
|
4
|
+
|
|
5
|
+
const container = document.getElementById("root");
|
|
6
|
+
if (container) {
|
|
7
|
+
if (container.firstChild) {
|
|
8
|
+
hydrateRoot(container, <App />);
|
|
9
|
+
} else {
|
|
10
|
+
createRoot(container).render(<App />);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
const [count, setCount] = useState(0);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div>
|
|
9
|
+
<h1>
|
|
10
|
+
<span>Hello, <%= projectName %>!</span>
|
|
11
|
+
<button onClick={() => setCount(count + 1)}>
|
|
12
|
+
Clicked {count} times
|
|
13
|
+
</button>
|
|
14
|
+
</h1>
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const container = document.getElementById('root');
|
|
20
|
+
if (container) {
|
|
21
|
+
const root = createRoot(container);
|
|
22
|
+
root.render(
|
|
23
|
+
<React.StrictMode>
|
|
24
|
+
<App />
|
|
25
|
+
</React.StrictMode>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
mode: "development" as const,
|
|
3
|
+
bundler: "<%= bundler %>",
|
|
4
|
+
plugins: ["@bundlekit/plugin-react"],
|
|
5
|
+
config: {
|
|
6
|
+
development: {
|
|
7
|
+
target: "web" as const,
|
|
8
|
+
publicPath: "/",
|
|
9
|
+
entry: <% if (ssr) { %>"src/entry-client.tsx"<% } else { %>"src/index.tsx"<% } %>,<% if (!ssr) { %>
|
|
10
|
+
pages: [
|
|
11
|
+
{ entry: "src/index.tsx", filename: "index.html", template: "public/index.html", inject: "body" },
|
|
12
|
+
],<% } %>
|
|
13
|
+
output: { dir: "dist", filename: "[name].js", formats: "umd" as const },
|
|
14
|
+
alias: { "@": "src" },
|
|
15
|
+
externals: [],
|
|
16
|
+
js: { sourcemap: true, minify: false, splitChunks: true },
|
|
17
|
+
devServer: { open: true, proxy: {}, https: false, host: "0.0.0.0", port: 3000 },<% if (ssr) { %>
|
|
18
|
+
ssr: {
|
|
19
|
+
entry: "src/entry-server.tsx",
|
|
20
|
+
output: { dir: "dist/server", filename: "server.cjs", formats: "commonjs" as const },
|
|
21
|
+
externals: "auto" as const,
|
|
22
|
+
template: "public/index.html",
|
|
23
|
+
placeholder: "<!--ssr-outlet-->",
|
|
24
|
+
dev: true,
|
|
25
|
+
},<% } %>
|
|
26
|
+
},
|
|
27
|
+
production: {
|
|
28
|
+
target: "web" as const,
|
|
29
|
+
publicPath: "/",
|
|
30
|
+
entry: <% if (ssr) { %>"src/entry-client.tsx"<% } else { %>"src/index.tsx"<% } %>,<% if (!ssr) { %>
|
|
31
|
+
pages: [
|
|
32
|
+
{ entry: "src/index.tsx", filename: "index.html", template: "public/index.html", inject: "body" },
|
|
33
|
+
],<% } %>
|
|
34
|
+
output: { dir: "dist", filename: "[name].[contenthash:8].js", formats: "umd" as const },
|
|
35
|
+
alias: { "@": "src" },
|
|
36
|
+
externals: [],
|
|
37
|
+
js: { sourcemap: false, minify: true, splitChunks: true },<% if (ssr) { %>
|
|
38
|
+
ssr: {
|
|
39
|
+
entry: "src/entry-server.tsx",
|
|
40
|
+
output: { dir: "dist/server", filename: "server.cjs", formats: "commonjs" as const },
|
|
41
|
+
externals: "auto" as const,
|
|
42
|
+
template: "public/index.html",
|
|
43
|
+
placeholder: "<!--ssr-outlet-->",
|
|
44
|
+
},<% } %>
|
|
45
|
+
},
|
|
46
|
+
} as any,
|
|
47
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
7
|
+
|
|
8
|
+
http.createServer((req, res) => {
|
|
9
|
+
const requestPath = req.url?.split('?')[0];
|
|
10
|
+
const requestMethod = req.method?.toLowerCase();
|
|
11
|
+
const mockFilePath = path.resolve(
|
|
12
|
+
__dirname,
|
|
13
|
+
`./resources${requestPath}.${requestMethod}.json`
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const content = fs.readFileSync(mockFilePath, 'utf-8');
|
|
18
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
19
|
+
res.write(content);
|
|
20
|
+
res.end();
|
|
21
|
+
} catch (_error) {
|
|
22
|
+
res.writeHead(404);
|
|
23
|
+
res.end(JSON.stringify({ error: 'not found' }));
|
|
24
|
+
}
|
|
25
|
+
}).listen(4000, () => {
|
|
26
|
+
console.log('Mock server running on http://localhost:4000');
|
|
27
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= projectName %>",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "<%= description %>",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"clean": "rimraf dist",
|
|
7
|
+
"dev": "bundlekit-service serve --bundler <%= bundler %> --mode development",
|
|
8
|
+
"build": "bundlekit-service build --bundler <%= bundler %> --mode production"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"react": "^18.2.0",
|
|
12
|
+
"react-dom": "^18.2.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@bundlekit/service": "workspace:^",
|
|
16
|
+
"@bundlekit/plugin-react": "workspace:^",
|
|
17
|
+
"@types/react": "^18.2.0",
|
|
18
|
+
"@types/react-dom": "^18.2.0",
|
|
19
|
+
"rimraf": "^5.0.1",
|
|
20
|
+
"typescript": "^5.8.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= projectName %></title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"><!--ssr-outlet--></div>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
const App: React.FC = () => {
|
|
4
|
+
const [count, setCount] = useState(0);
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<div>
|
|
8
|
+
<h1>
|
|
9
|
+
<span>Hello, <%= projectName %>!</span>
|
|
10
|
+
<button onClick={() => setCount(count + 1)}>
|
|
11
|
+
Clicked {count} times
|
|
12
|
+
</button>
|
|
13
|
+
</h1>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default App;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { hydrateRoot, createRoot } from "react-dom/client";
|
|
3
|
+
import App from "./App";
|
|
4
|
+
|
|
5
|
+
const container = document.getElementById("root");
|
|
6
|
+
if (container) {
|
|
7
|
+
// SSR 模式:服务端已经吐了 HTML,用 hydrateRoot 复用 DOM
|
|
8
|
+
// CSR 模式:DOM 是空的,回退到 createRoot
|
|
9
|
+
if (container.firstChild) {
|
|
10
|
+
hydrateRoot(container, <App />);
|
|
11
|
+
} else {
|
|
12
|
+
createRoot(container).render(<App />);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { renderToString } from "react-dom/server";
|
|
3
|
+
import App from "./App";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 服务端渲染入口
|
|
7
|
+
*
|
|
8
|
+
* @param url 当前请求路径,用于路由匹配
|
|
9
|
+
* @returns HTML 字符串,将由 service 替换到 index.html 的 <!--ssr-outlet--> 占位
|
|
10
|
+
*/
|
|
11
|
+
export function render(url: string): string {
|
|
12
|
+
return renderToString(<App />);
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
|
|
4
|
+
const App: React.FC = () => {
|
|
5
|
+
const [count, setCount] = useState(0);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div>
|
|
9
|
+
<h1>
|
|
10
|
+
<span>Hello, <%= projectName %>!</span>
|
|
11
|
+
<button onClick={() => setCount(count + 1)}>
|
|
12
|
+
Clicked {count} times
|
|
13
|
+
</button>
|
|
14
|
+
</h1>
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const container = document.getElementById('root');
|
|
20
|
+
if (container) {
|
|
21
|
+
const root = createRoot(container);
|
|
22
|
+
root.render(
|
|
23
|
+
<React.StrictMode>
|
|
24
|
+
<App />
|
|
25
|
+
</React.StrictMode>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": false,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"noFallthroughCasesInSwitch": true,
|
|
14
|
+
"moduleResolution": "node",
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"noEmit": true,
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"paths": {
|
|
20
|
+
"@/*": ["./src/*"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"include": ["src/**/*"]
|
|
24
|
+
}
|