@mpxjs/vue-cli-plugin-mpx-ssr 2.1.0

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/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @mpxjs/vue-cli-plugin-mpx-plugin-ssr
2
+
3
+ web ssr插件(目前仅支持 `web`)
@@ -0,0 +1,57 @@
1
+ const { normalizeCommandArgs } = require('@mpxjs/cli-shared-utils')
2
+ const { addBaseWebpackConfig } = require('../../config/base.config')
3
+ const { addBuildWebpackConfig } = require('../../config/build.config')
4
+ const { resolveBuildWebpackConfigByTarget } = require('@mpxjs/vue-cli-plugin-mpx/config')
5
+ const { getCurrentTarget } = require('@mpxjs/cli-shared-utils')
6
+ const { handleWebpackDone } = require('@mpxjs/vue-cli-plugin-mpx/utils/webpack')
7
+ const webpack = require('webpack')
8
+ const fs = require('fs-extra')
9
+
10
+ const defaults = {
11
+ clean: true
12
+ }
13
+
14
+ module.exports.registerBuildCommand = function (api, options) {
15
+ api.registerCommand(
16
+ 'build:ssr',
17
+ {
18
+ description: 'mpx production',
19
+ usage: 'mpx-cli-service build ssr'
20
+ },
21
+ function build (args) {
22
+ normalizeCommandArgs(args, defaults)
23
+ if (args.clean) {
24
+ fs.removeSync(options.outputDir)
25
+ }
26
+
27
+ const getBaseConfig = (ssrMode) => {
28
+ api.chainWebpack((config) => {
29
+ addBaseWebpackConfig(api, options, args, config, { ssrMode })
30
+ addBuildWebpackConfig(api, options, args, config, { ssrMode })
31
+ })
32
+ const target = getCurrentTarget()
33
+ // 根据目标获取构建配置
34
+ const webpackConfig = resolveBuildWebpackConfigByTarget(api, options, target, args)
35
+ return {
36
+ webpackConfig,
37
+ target
38
+ }
39
+ }
40
+
41
+ const buildService = (ssrMode) => {
42
+ return new Promise((resolve, reject) => {
43
+ const { webpackConfig, target } = getBaseConfig(ssrMode)
44
+ webpack(webpackConfig, (err, stats) => {
45
+ handleWebpackDone(err, stats, target, api)
46
+ .then((...res) => {
47
+ resolve(...res)
48
+ })
49
+ .catch(reject)
50
+ })
51
+ })
52
+ }
53
+
54
+ return Promise.all([buildService('client'), buildService('server')])
55
+ }
56
+ )
57
+ }
@@ -0,0 +1,49 @@
1
+ const { normalizeCommandArgs } = require('@mpxjs/cli-shared-utils')
2
+ const { serveWeb } = require('@mpxjs/vue-cli-plugin-mpx/commands/serve/web')
3
+ const { serveServer } = require('./serveServer')
4
+ const { addBaseWebpackConfig } = require('../../config/base.config')
5
+ const { addServeWebpackConfig } = require('../../config/serve.config')
6
+
7
+ const defaults = {
8
+ port: 3000
9
+ }
10
+
11
+ module.exports.registerServeCommand = function (api, options) {
12
+ api.registerCommand(
13
+ 'serve:ssr',
14
+ {
15
+ description: 'mpx development',
16
+ usage: 'mpx-cli-service serve ssr'
17
+ },
18
+ async function build (args) {
19
+ normalizeCommandArgs(args, defaults)
20
+
21
+ const getBaseConfig = (ssrMode) => {
22
+ const isServer = ssrMode === 'server'
23
+ const port = options.pluginOptions?.SSR?.devClientPort || defaults.port
24
+ options.publicPath = isServer ? '/' : `http://localhost:${port}/`
25
+ api.chainWebpack((config) => {
26
+ addBaseWebpackConfig(api, options, args, config, { ssrMode })
27
+ addServeWebpackConfig(api, options, args, config, { ssrMode })
28
+ })
29
+ }
30
+
31
+ const buildService = (ssrMode) => {
32
+ return new Promise((resolve, reject) => {
33
+ getBaseConfig(ssrMode)
34
+ if (ssrMode === 'client') {
35
+ serveWeb(api, options, args).then((...res) => {
36
+ resolve(...res)
37
+ }).catch(reject)
38
+ } else {
39
+ serveServer(api, options, args).then((...res) => {
40
+ resolve(...res)
41
+ }).catch(reject)
42
+ }
43
+ })
44
+ }
45
+
46
+ Promise.all([buildService('client'), buildService('server')])
47
+ }
48
+ )
49
+ }
@@ -0,0 +1,56 @@
1
+ const { resolveServeWebpackConfigByTarget } = require('@mpxjs/vue-cli-plugin-mpx/config')
2
+ const { getCurrentTarget } = require('@mpxjs/cli-shared-utils/lib')
3
+ const { getReporter } = require('@mpxjs/vue-cli-plugin-mpx/utils/reporter')
4
+ const { chalk } = require('@vue/cli-shared-utils')
5
+ const webpack = require('webpack')
6
+ const path = require('path')
7
+ const MemoryFS = require('memory-fs')
8
+ const { setServerBundle } = require('@mpxjs/cli-shared-utils')
9
+
10
+ /** @type {import('@vue/cli-service').ServicePlugin} */
11
+ module.exports.serveServer = async (api, options, args) => {
12
+ // resolve webpack config
13
+ const target = getCurrentTarget()
14
+ const webpackConfig = resolveServeWebpackConfigByTarget(
15
+ api,
16
+ options,
17
+ target,
18
+ args
19
+ )
20
+
21
+ // create compiler
22
+ const serverCompiler = webpack(webpackConfig)
23
+
24
+ const mfs = new MemoryFS()
25
+ // 指定输出到的内存流中
26
+ serverCompiler.outputFileSystem = mfs
27
+
28
+ return new Promise((resolve, reject) => {
29
+ serverCompiler.watch({}, (err, stats) => {
30
+ if (err) {
31
+ console.error(err)
32
+ return
33
+ }
34
+ stats = stats.toJson()
35
+ stats.errors.forEach(error => console.error(error))
36
+ stats.warnings.forEach(warn => console.warn(warn))
37
+
38
+ const bundlePath = path.join(webpackConfig.output.path, 'vue-ssr-server-bundle.json')
39
+
40
+ const serverManifest = JSON.parse(mfs.readFileSync(bundlePath, 'utf-8'))
41
+
42
+ setServerBundle(serverManifest)
43
+
44
+ getReporter()._renderStates([{
45
+ message: 'new server bundle generated',
46
+ color: 'green'
47
+ }])
48
+ })
49
+ try {
50
+ require(api.resolve('server/dev.server'))
51
+ } catch (e) {
52
+ reject(e)
53
+ }
54
+ resolve()
55
+ })
56
+ }
@@ -0,0 +1,19 @@
1
+ const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
2
+ const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
3
+
4
+ module.exports.addBaseWebpackConfig = function (api, options = {}, args, config, compilerConfig) {
5
+ const isServer = compilerConfig.ssrMode === 'server'
6
+
7
+ config.target(isServer ? 'node' : 'web')
8
+
9
+ config.output
10
+ .libraryTarget(isServer ? 'commonjs2' : undefined)
11
+
12
+ if (isServer) {
13
+ config.optimization.splitChunks(false)
14
+ }
15
+
16
+ config
17
+ .plugin(`${isServer ? 'server-plugin' : 'client-plugin'}`)
18
+ .use(isServer ? VueSSRServerPlugin : VueSSRClientPlugin)
19
+ }
@@ -0,0 +1,8 @@
1
+ module.exports.addBuildWebpackConfig = function (api, options = {}, args, config, compilerConfig) {
2
+ const isServer = compilerConfig.ssrMode === 'server'
3
+
4
+ config.cache({
5
+ ...config.get('cache'),
6
+ name: isServer ? 'build-serverBundleCache' : 'build-clientBundleCache'
7
+ })
8
+ }
@@ -0,0 +1,10 @@
1
+ module.exports.addServeWebpackConfig = function (api, options = {}, args, config, compilerConfig) {
2
+ const isServer = compilerConfig.ssrMode === 'server'
3
+
4
+ config.cache({
5
+ ...config.get('cache'),
6
+ name: isServer ? 'dev-serverBundleCache' : 'dev-clientBundleCache'
7
+ })
8
+
9
+ config.devServer.port(options.pluginOptions?.SSR?.devClientPort || 3000)
10
+ }
@@ -0,0 +1,15 @@
1
+ module.exports = function (api, options) {
2
+ api.render('./template', options)
3
+ api.extendPackage({
4
+ scripts: {
5
+ 'serve:ssr': 'mpx-cli-service serve:ssr',
6
+ 'build:ssr': 'mpx-cli-service build:ssr'
7
+ },
8
+ devDependencies: {
9
+ axios: '^1.6.0',
10
+ express: '^4.18.2',
11
+ 'serve-favicon': '^2.5.0',
12
+ 'vue-server-renderer': '^2.7.14'
13
+ }
14
+ })
15
+ }
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport"
6
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover">
7
+ <meta name="format-detection" content="telephone=no">
8
+ <meta name="x5-cache" content="disable">
9
+ <title></title>
10
+ </head>
11
+ <body>
12
+ <!--vue-ssr-outlet-->
13
+ </body>
14
+ </html>
@@ -0,0 +1,44 @@
1
+ const express = require('express')
2
+ const fs = require('fs')
3
+
4
+ const app = express()
5
+
6
+ // 创建渲染器 获得一个createBundleRenderer
7
+ const { createBundleRenderer } = require('vue-server-renderer')
8
+ const serverBundle = require('../dist/web/vue-ssr-server-bundle.json')
9
+ const clientManifest = require('../dist/web/vue-ssr-client-manifest.json')
10
+ const template = fs.readFileSync('../public/index.ssr.html', 'utf-8')
11
+
12
+ app.use(express.static('../dist/web'))
13
+
14
+ const startServer = async () => {
15
+ // 前端请求返回数据
16
+ app.get('*', async (req, res) => {
17
+ try {
18
+ const renderer = createBundleRenderer(serverBundle, {
19
+ runInNewContext: false,
20
+ template,
21
+ clientManifest
22
+ })
23
+ const context = { url: req.url }
24
+ renderer.renderToString(context, (err, html) => {
25
+ if (err) {
26
+ console.log(err)
27
+ res.status(500).end('Internal Server Error')
28
+ return
29
+ }
30
+ res.end(html)
31
+ })
32
+ } catch (error) {
33
+ console.log(error)
34
+ res.status(500).send('服务器内部错误')
35
+ }
36
+ })
37
+
38
+ /* 服务启动 */
39
+ const port = 8091
40
+ app.listen(port, () => {
41
+ console.log(`server started at localhost:${port}`)
42
+ })
43
+ }
44
+ startServer()
@@ -0,0 +1,63 @@
1
+ const express = require('express')
2
+ const { getServerBundle } = require('@mpxjs/mpx-cli-service')
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+
6
+ // 创建渲染器 获得一个createBundleRenderer
7
+ const { createBundleRenderer } = require('vue-server-renderer')
8
+
9
+ const axios = require('axios')
10
+
11
+ const favicon = require('serve-favicon')
12
+
13
+ const template = fs.readFileSync(path.resolve('public/index.ssr.html'), 'utf-8')
14
+
15
+ const vueConfig = require('../vue.config.js')
16
+
17
+ const app = express()
18
+
19
+ app.use(favicon(path.resolve('public/favicon.ico')))
20
+
21
+ const getRenderer = async () => {
22
+ const clientPort = vueConfig.pluginOptions?.SSR?.devClientPort || 3000
23
+ const clientManifest = await axios.get(
24
+ `http://localhost:${clientPort}/vue-ssr-client-manifest.json`
25
+ )
26
+ const serverManifest = getServerBundle()
27
+
28
+ return {
29
+ clientManifest: clientManifest.data,
30
+ serverManifest: serverManifest
31
+ }
32
+ }
33
+
34
+ const startServer = async () => {
35
+ app.get('*', async (req, res) => {
36
+ try {
37
+ const { clientManifest, serverManifest } = await getRenderer()
38
+ const renderer = createBundleRenderer(serverManifest, {
39
+ runInNewContext: false,
40
+ template,
41
+ clientManifest
42
+ })
43
+ const context = { url: req.url }
44
+ renderer.renderToString(context, (err, html) => {
45
+ if (err) {
46
+ res.status(500).end('Internal Server Error')
47
+ return
48
+ }
49
+ res.end(html)
50
+ })
51
+ } catch (error) {
52
+ console.log(error)
53
+ res.status(500).send('服务器内部错误')
54
+ }
55
+ })
56
+
57
+ /* 服务启动 */
58
+ const port = 8091
59
+ app.listen(port, () => {
60
+ console.log(`server started at localhost:${port}`)
61
+ })
62
+ }
63
+ startServer()
@@ -0,0 +1,57 @@
1
+ <script>
2
+ import mpx, { createApp } from '@mpxjs/core'
3
+ import apiProxy from '@mpxjs/api-proxy'
4
+ import { createPinia } from '@mpxjs/pinia'
5
+
6
+ mpx.use(apiProxy, { usePromise: true })
7
+
8
+ mpx.config.webRouteConfig = {
9
+ mode: 'history'
10
+ }
11
+
12
+ createApp({
13
+ onLaunch() {
14
+ //
15
+ },
16
+ onAppInit() {
17
+ const pinia = createPinia()
18
+ return {
19
+ pinia
20
+ }
21
+ },
22
+ onSSRAppCreated({ pinia, router, app, context }) {
23
+ return new Promise((resolve, reject) => {
24
+ router.push(context.url)
25
+ router.onReady(() => {
26
+ context.rendered = () => {
27
+ context.state = pinia.state.value
28
+ }
29
+ resolve(app)
30
+ }, reject)
31
+ })
32
+ }
33
+ })
34
+ </script>
35
+
36
+ <style>
37
+ /*此处编写全局样式*/
38
+ </style>
39
+
40
+ <script type="application/json">
41
+ {
42
+ "pages": [
43
+ "./pages/index"
44
+ ]
45
+ }
46
+ </script>
47
+
48
+ <!--也可以通过以下形式用js输出json,便于书写注释和使用条件编译-->
49
+
50
+ <!--<script name="json">-->
51
+ <!-- // 可以写注释,通过defs注入的常量做一些判断之类的操作-->
52
+ <!-- module.exports = {-->
53
+ <!-- pages: [-->
54
+ <!-- './pages/index'-->
55
+ <!-- ]-->
56
+ <!-- }-->
57
+ <!--</script>-->
package/index.js ADDED
@@ -0,0 +1,14 @@
1
+ const { registerServeCommand } = require('./commands/serve')
2
+ const { registerBuildCommand } = require('./commands/build')
3
+
4
+ module.exports = function (api, options) {
5
+ registerServeCommand(api, options)
6
+ registerBuildCommand(api, options)
7
+ }
8
+
9
+ module.exports.defaultModes = {
10
+ 'serve:ssr': 'development',
11
+ 'build:ssr': 'production'
12
+ }
13
+
14
+ module.exports.after = ['@mpxjs/vue-cli-plugin-mpx']
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@mpxjs/vue-cli-plugin-mpx-ssr",
3
+ "version": "2.1.0",
4
+ "description": " web ssr plugin for mpx-cli",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "dependencies": {
10
+ "memory-fs": "^0.5.0",
11
+ "fs-extra": "^9.1.0",
12
+ "@mpxjs/vue-cli-plugin-mpx": "^2.1.0",
13
+ "@mpxjs/cli-shared-utils": "^2.0.7"
14
+ },
15
+ "devDependencies": {
16
+ "axios": "^1.6.0",
17
+ "express": "^4.18.2",
18
+ "serve-favicon": "^2.5.0",
19
+ "vue-server-renderer": "^2.7.14"
20
+ },
21
+ "peerDependencies": {
22
+ "vue-server-renderer": "^2.7.14"
23
+ },
24
+ "keywords": [],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org",
29
+ "access": "public"
30
+ }
31
+ }