仓库地址
架构设计
- 脚手架命令行工具: ssr
提供了常用的命令:start build deploy
本地开发环境
- 执行
ssr start
// 核心执行代码如下
// 插件通过项目中的plugin.js文件配置
const plugin = loadPlugin()
// start client webpack dev server
await plugin.clientPlugin?.start?.(argv)
// 启动midway
await plugin.serverPlugin?.start?.(argv)
- plugin.js 中声明
serverPlugin clientPlugin
插件
const { midwayPlugin } = require('ssr-plugin-midway')
const { reactPlugin } = require('ssr-plugin-react')
module.exports = {
serverPlugin: midwayPlugin(),
clientPlugin: reactPlugin()
}
- ssr-plugin-react 逻辑
// 依赖webpack-chain
import * as WebpackChain from 'webpack-chain'
// 包装了webpack的功能
import { startClientServer, startServerBuild, startClientBuild } from 'ssr-webpack'
// 获取客户端和服务端构建的配置
import { getClientWebpack, getServerWebpack } from './config'
export function reactPlugin () {
return {
name: 'plugin-react',
// 本地开发环境
start: async () => {
// 使用weback-chain 来配置webpack
const serverConfigChain = new WebpackChain()
// 调用的是 ssr-webpack 里面的方法
// server端开发环境的配置 见[附录1]
await startServerBuild(getServerWebpack(serverConfigChain))
const clientConfigChain = new WebpackChain()
// 开发环境client端的配置 见[附录2]
await startClientServer(getClientWebpack(clientConfigChain))
},
build: async () => {
const serverConfigChain = new WebpackChain()
await startServerBuild(getServerWebpack(serverConfigChain))
const clientConfigChain = new WebpackChain()
await startClientBuild(getClientWebpack(clientConfigChain))
}
}
}
- ssr-webpack
import { webpackPromisify } from '../utils/promisify'
const startServerBuild = async (webpackConfig: webpack.Configuration) => {
const { webpackStatsOption } = loadConfig()
// 这里将webpack包装成了一个promise对象 方便结合await使用
const stats = await webpackPromisify(webpackConfig)
console.log(stats.toString(webpackStatsOption))
}
- promisify逻辑
比较简单,利用了nodejs自带的模块 util提供的promisify 函数;
这个函数能够将xxx(arg1, (err, res)=> {}) 这种格式的函数转换成一个promise函数
import { promisify } from 'util'
import * as webpack from 'webpack'
const webpackPromisify = promisify(webpack)
export {
webpackPromisify
}
附录:
- 开发环境server bundle构建配置
{
"mode": "development",
"devtool": "eval-source-map",
"target": "node",
"watch": true,
"output": {
"path": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/build/server",
"filename": "[name].server.js",
"libraryTarget": "commonjs"
},
"resolve": {
"alias": {
"@": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/web",
"react": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react/index.js",
"react-router": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react-router/index.js",
"react-router-dom": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react-router-dom/index.js"
},
"extensions": [
".web.mjs",
".mjs",
".web.js",
".js",
".web.ts",
".ts",
".web.tsx",
".tsx",
".json",
".web.jsx",
".jsx",
".vue"
],
"modules": [
"node_modules",
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules",
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/"
]
},
"module": {
"strictExportPresence": true,
"rules": [
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/url-loader/dist/cjs.js",
"options": {
"limit": 10000,
"name": "static/[name].[hash:8].[ext]",
"esModule": false,
"fallback": {
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
}
}
]
},
{
"test": {},
"exclude": [
{},
{}
],
"use": [
{
"loader": "babel-loader",
"options": {
"cacheDirectory": true,
"cacheCompression": false,
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
[
"react-app",
{
"flow": false,
"typescript": true
}
]
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "lib",
"style": "css"
}
]
]
}
}
]
},
{
"test": {},
"exclude": [
[
{},
{}
]
],
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 1,
"modules": true
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
}
]
},
{
"test": {},
"include": [
[
{},
{}
]
],
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 1,
"modules": false
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 2,
"modules": true
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/less-loader/dist/cjs.js"
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
]
}
]
},
"plugins": [
{
"options": {
"filename": "static/css/[name].css",
"ignoreOrder": false,
"chunkFilename": "static/css/[name].chunk.css"
}
},
{
"definitions": {
"__isBrowser__": false
}
}
],
"entry": {
"Page": [
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/ssr-plugin-react/cjs/entry/server-entry.js"
]
}
}
- 开发环境client的webpack配置
{
"mode": "development",
"devtool": "cheap-module-source-map",
"output": {
"path": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/build/client",
"filename": "static/js/[name].js",
"chunkFilename": "static/js/[name].chunk.js",
"publicPath": "/"
},
"resolve": {
"alias": {
"@": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/web",
"react": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react/index.js",
"react-router": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react-router/index.js",
"react-router-dom": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/react-router-dom/index.js"
},
"extensions": [
".web.mjs",
".mjs",
".web.js",
".js",
".web.ts",
".ts",
".web.tsx",
".tsx",
".json",
".web.jsx",
".jsx",
".vue"
],
"modules": [
"node_modules",
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules",
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/"
]
},
"module": {
"strictExportPresence": true,
"rules": [
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/url-loader/dist/cjs.js",
"options": {
"limit": 10000,
"name": "static/[name].[hash:8].[ext]",
"esModule": false,
"fallback": {
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
}
}
]
},
{
"test": {},
"exclude": [
{}
],
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/babel-loader/lib/index.js",
"options": {
"cacheDirectory": true,
"cacheCompression": false,
"sourceType": "unambiguous",
"presets": [
[
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/@babel/preset-env/lib/index.js",
{
"modules": false
}
],
[
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/babel-preset-react-app/index.js",
{
"flow": false,
"typescript": true
}
]
],
"plugins": [
[
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/@babel/plugin-transform-runtime/lib/index.js",
{
"regenerator": false,
"corejs": false,
"helpers": true
}
],
[
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/babel-plugin-import/lib/index.js",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css"
}
]
]
}
}
]
},
{
"test": {},
"exclude": [
[
{},
{}
]
],
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 1,
"modules": true
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
}
]
},
{
"test": {},
"include": [
[
{},
{}
]
],
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 1,
"modules": false
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-hot-loader/index.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/mini-css-extract-plugin/dist/loader.js"
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/css-loader/index.js",
"options": {
"importLoaders": 2,
"modules": true
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/postcss-loader/src/index.js",
"options": {
"ident": "postcss"
}
},
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/less-loader/dist/cjs.js"
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
]
},
{
"test": {},
"use": [
{
"loader": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/file-loader/dist/cjs.js",
"options": {
"name": "static/[name].[hash:8].[ext]",
"esModule": false
}
}
]
}
]
},
"optimization": {
"runtimeChunk": true,
"splitChunks": {
"chunks": "initial",
"name": false,
"cacheGroups": {
"vendors": {
"name": "vendor"
}
}
}
},
"plugins": [
{
"options": {
"filename": "static/css/[name].css",
"ignoreOrder": false,
"chunkFilename": "static/css/[name].chunk.css"
}
},
{
"definitions": {
"__isBrowser__": true
}
},
{
"appPath": "/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr"
},
{
"opts": {
"publicPath": "/",
"basePath": "",
"fileName": "asset-manifest.json",
"transformExtensions": {},
"writeToFileEmit": false,
"seed": null,
"filter": null,
"map": null,
"generate": null,
"sort": null
}
}
],
"entry": {
"Page": [
"/Users/oker/projects/company/tmp/ssr/ykfe-ssr/ssr/example/midway-react-ssr/node_modules/ssr-plugin-react/cjs/entry/client-entry.js"
]
}
}