研究ssr
This commit is contained in:
3
gpt-query/one/.babelrc
Normal file
3
gpt-query/one/.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
19
gpt-query/one/esbuild.config.mjs
Normal file
19
gpt-query/one/esbuild.config.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import { build } from 'esbuild';
|
||||
|
||||
build({
|
||||
entryPoints: ['./src/client.js'], // 入口文件
|
||||
bundle: true, // 打包所有依赖
|
||||
outfile: './public/client.js', // 输出文件
|
||||
minify: false, // 压缩代码
|
||||
sourcemap: false, // 生成 Source Map
|
||||
platform: 'browser', // 指定运行环境为浏览器
|
||||
target: ['es6'], // 目标环境
|
||||
loader: { '.jsx': 'jsx', '.js': 'jsx' }, // 处理 JSX 文件
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Client build complete!');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Build failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
20
gpt-query/one/esbuild.config.server.mjs
Normal file
20
gpt-query/one/esbuild.config.server.mjs
Normal file
@@ -0,0 +1,20 @@
|
||||
import { build } from 'esbuild';
|
||||
|
||||
build({
|
||||
entryPoints: ['./server.tsx'], // 入口文件
|
||||
bundle: true, // 打包所有依赖
|
||||
outfile: './server.js', // 输出文件
|
||||
minify: false, // 压缩代码
|
||||
sourcemap: false, // 生成 Source Map
|
||||
platform: 'node', // 指定运行环境为浏览器
|
||||
target: ['es6'], // 目标环境
|
||||
external: ['node_modules/*'], // 不打包 node_modules
|
||||
loader: { '.jsx': 'jsx', '.tsx': 'tsx', '.js': 'jsx' }, // 处理 JSX 文件
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Client build complete!');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Build failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
25
gpt-query/one/package.json
Normal file
25
gpt-query/one/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "react-ssr-example",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"build2": "babel src --out-dir public",
|
||||
"build": "rollup -c",
|
||||
"start": "node server.js",
|
||||
"start2": "babel-node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.0",
|
||||
"express": "^4.21.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"rollup": "^4.27.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.25.9",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/node": "^7.26.0",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@babel/preset-react": "^7.25.9"
|
||||
}
|
||||
}
|
||||
3706
gpt-query/one/pnpm-lock.yaml
generated
Normal file
3706
gpt-query/one/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
gpt-query/one/public/App.js
Normal file
29
gpt-query/one/public/App.js
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports["default"] = void 0;
|
||||
var _react = _interopRequireWildcard(require("react"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
|
||||
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
||||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
||||
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
||||
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
||||
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
||||
var App = function App(_ref) {
|
||||
var initialState = _ref.initialState;
|
||||
var _useState = (0, _react.useState)(initialState.name),
|
||||
_useState2 = _slicedToArray(_useState, 2),
|
||||
name = _useState2[0],
|
||||
setName = _useState2[1];
|
||||
return /*#__PURE__*/_react["default"].createElement("div", {
|
||||
onClick: function onClick() {
|
||||
setName('Jane Doe');
|
||||
}
|
||||
}, "Hello World ", name);
|
||||
};
|
||||
var _default = exports["default"] = App;
|
||||
24579
gpt-query/one/public/client.js
Normal file
24579
gpt-query/one/public/client.js
Normal file
File diff suppressed because it is too large
Load Diff
7
gpt-query/one/public/client.js.map
Normal file
7
gpt-query/one/public/client.js.map
Normal file
File diff suppressed because one or more lines are too long
23
gpt-query/one/rollup.config.mjs
Normal file
23
gpt-query/one/rollup.config.mjs
Normal file
@@ -0,0 +1,23 @@
|
||||
import resolve from '@rollup/plugin-node-resolve'; // 解析模块
|
||||
import commonjs from '@rollup/plugin-commonjs'; // 转换 CommonJS 为 ESModules
|
||||
import babel from '@rollup/plugin-babel'; // Babel 支持
|
||||
// import { terser } from 'rollup-plugin-terser'; // 可选:压缩代码
|
||||
|
||||
export default {
|
||||
input: './src/client.js', // 入口文件
|
||||
output: {
|
||||
file: './public/client.js', // 输出文件
|
||||
format: 'iife', // 输出格式:立即执行函数 (适合浏览器)
|
||||
sourcemap: true, // 生成 Source Map 方便调试
|
||||
},
|
||||
plugins: [
|
||||
resolve(), // 解析 node_modules 中的依赖
|
||||
commonjs(), // 转换 CommonJS 模块
|
||||
babel({
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||
babelHelpers: 'bundled', // 使用打包后的 Babel helpers
|
||||
exclude: 'node_modules/**', // 排除 node_modules
|
||||
}),
|
||||
// terser(), // 可选:压缩输出代码
|
||||
],
|
||||
};
|
||||
40021
gpt-query/one/server.js
Normal file
40021
gpt-query/one/server.js
Normal file
File diff suppressed because one or more lines are too long
33
gpt-query/one/server.tsx
Normal file
33
gpt-query/one/server.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import express from 'express';
|
||||
import React from 'react';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
import App from './src/App';
|
||||
|
||||
const app = express();
|
||||
|
||||
// 静态文件服务
|
||||
app.use(express.static('public'));
|
||||
|
||||
// 首页路由
|
||||
app.get('/', (req, res) => {
|
||||
const initialState = { name: 'John Doe22' };
|
||||
const html = renderToString(<App initialState={initialState} />);
|
||||
|
||||
res.send(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>React SSR</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
<script>
|
||||
window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
|
||||
</script>
|
||||
<script type="module" src="/client.js"></script>
|
||||
</body>
|
||||
</html>`);
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log('Server is running at http://localhost:3000');
|
||||
});
|
||||
19
gpt-query/one/src/App.tsx
Normal file
19
gpt-query/one/src/App.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const App = ({ initialState }) => {
|
||||
const [name, setName] = useState(initialState.name);
|
||||
useEffect(() => {
|
||||
setName('Client'); // 仅客户端执行
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
onClick={() => {
|
||||
setName('Jane Doe233');
|
||||
}}
|
||||
>
|
||||
Hello World {name}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
7
gpt-query/one/src/client.js
Normal file
7
gpt-query/one/src/client.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import { hydrateRoot } from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
const initialState = window.__INITIAL_STATE__ || { name: 'Default Name' };
|
||||
|
||||
hydrateRoot(document.getElementById('root'), <App initialState={initialState} />);
|
||||
20
gpt-query/one/tsconfig.json
Normal file
20
gpt-query/one/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"noEmit": true,
|
||||
"emitDeclarationOnly": false,
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user