Есть ли еще один шаг в создании JS комплекта для Vue SSR? - PullRequest
1 голос
/ 05 февраля 2020

Я создаю Vue приложение SSR для рендеринга простой vue стороны сервера компонентов. После официального руководства по сайту vuejs я создал два файла ввода server-entry.js и client-entry.js, запись клиента работает нормально и без проблем отображает компонент. Однако, когда я создаю запись сервера, она собирается без проблем, давая мне js/<bundle>.js и css/<bundle>.css. Но когда я запускаю файл server.js с:

node src/server.js

, терминал показывает, что он работает и прослушивает порт 8080. Но когда я захожу на localhost: 8080. У меня следующая ошибка:

TypeError: createApp is not a function
    at server.get (/home/osama/projects/quran-embed/src/server.js:9:5)
    at Layer.handle [as handle_request] (/home/osama/projects/quran-embed/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/osama/projects/quran-embed/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/home/osama/projects/quran-embed/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/osama/projects/quran-embed/node_modules/express/lib/router/layer.js:95:5)
    at /home/osama/projects/quran-embed/node_modules/express/lib/router/index.js:281:22
    at param (/home/osama/projects/quran-embed/node_modules/express/lib/router/index.js:354:14)
    at param (/home/osama/projects/quran-embed/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/home/osama/projects/quran-embed/node_modules/express/lib/router/index.js:410:3)
    at next (/home/osama/projects/quran-embed/node_modules/express/lib/router/index.js:275:10)

Я не понимаю, почему она говорит мне, что createApp не является функцией, хотя это так.

ПРИМЕЧАНИЕ: I Я использую Vue CLI 3.

Вот соответствующие файлы:

app. js

// https://ssr.vuejs.org/guide/structure.html#code-structure-with-webpack
// app.js the universal entry

import Vue from 'vue'
import App from './App.vue'
import {createRouter} from './router'
import {createStore} from './store'

import './assets/scss/main.scss'

Vue.config.productionTip = false


// export a factory function for creating fresh app, router and store
// instances
export function createApp() {

    // create router instance
    const router = createRouter()

    // create store instance
    const store = createStore()

    // inject router into root Vue instance
    const app = new Vue({
        router,
        store,
        render: h => h(App)
    })

    // return both the app and the router
    return {app, router}
}

entry-server. js

// entry-server.js
import {createApp} from './app.js'

export default context => {
    // since there could potentially be asynchronous route hooks or components,
    // we will be returning a Promise so that the server can wait until
    // everything is ready before rendering.
    return new Promise((resolve, reject) => {
        const {app, router} = createApp()

        // set server-side router's location
        router.push(context.url)

        // wait until router has resolved possible async components and hooks
        router.onReady(() => {
            const matchedComponents = router.getMatchedComponents()
            // no matched routes, reject with 404
            if (!matchedComponents.length) {
                return reject({code: 404})
            }

            // the Promise should resolve to the app instance so it can be rendered
            resolve(app)
        }, reject)
    })
}

сервер. js

// server.js
const createApp = require('../dist/js/quran-embed.js');
const renderer = require('vue-server-renderer').createRenderer();
const server = require('express')();


server.get('*', (req, res) => {
    const context = {url: req.url};
    createApp(context).then(app => {
        renderer.renderToString(app, (err, html) => {
            if (err) {
                if (err.code === 404) {
                    res.status(404).end('Page not found')
                } else {
                    res.status(500).end('Internal Server Error')
                }
            } else {
                res.end(`
                  <!DOCTYPE html>
                  <html lang="en">
                    <head><title>Hello</title></head>
                    <body>${html}</body>
                  </html>
                `)
            }
        })
    })
});

server.listen(8080);

vue .config. js

const webpack = require('webpack')
module.exports = {
    css: {
        extract: {
            filename: 'css/quran-embed.css',
        },
        // extract: false,
    },
    configureWebpack: {
        output: {
            filename: 'js/quran-embed.js',
            libraryTarget: 'commonjs2'
        },
        target: 'node',
        plugins: [
            new webpack.optimize.LimitChunkCountPlugin({
                maxChunks: 1
            }),

        ]
    },
    chainWebpack:
        config => {
            config.optimization.delete('splitChunks')
        },
    filenameHashing: false
}

пакет. json

{
  "name": "quran-embed",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve-client": "vue-cli-service serve src/entry-client.js",
    "build-client": "vue-cli-service build src/entry-client.js",
    "build-server": "cross-env NODE_ENV=production vue-cli-service build src/entry-server.js",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "at-ui": "^1.3.3",
    "at-ui-style": "^1.5.1",
    "axios": "^0.19.2",
    "bootstrap-v4-rtl": "^4.4.1-1",
    "cross-env": "^7.0.0",
    "document-register-element": "^1.11.0",
    "express": "^4.17.1",
    "jsdom": "^16.1.0",
    "lodash": "^4.17.13",
    "moment": "^2.22.2",
    "vue": "^2.5.16",
    "vue-custom-element": "^3.2.2",
    "vue-router": "^3.0.1",
    "vue-server-renderer": "^2.5.16",
    "vuex": "^3.0.1",
    "webpack": "^4.16.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.4.1",
    "@vue/cli-plugin-eslint": "^3.4.1",
    "@vue/cli-service": "^3.5.3",
    "@vue/eslint-config-standard": "^3.0.0-rc.5",
    "node-sass": "^4.11.0",
    "sass-loader": "^7.0.3",
    "vue-template-compiler": "^2.5.16"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "@vue/standard"
    ],
    "rules": {},
    "parserOptions": {
      "parser": "babel-eslint"
    }
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {}
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

Если вы посмотрите на файл package.json, вы можете найти скрипт build-server, который я использую для сборки пакета для SSR.

Я не уверен, что моя проблема с createApp не была идентифицирована как функция связана с моей настройкой или это просто ES6 / Javascript вещь.

Любая помощь по этому вопросу будет высоко ценится.

1 Ответ

0 голосов
/ 09 марта 2020

Проблема в том, что вы смешиваете export с require(), что считается плохой практикой .

Вы можете попытаться переместить createApp в client-entry.js и использовать bundleRenderer вместо classi c рендеринга. Однако для этого требуется дополнительная настройка, и вы можете найти действительно хороший пример того, как это сделать здесь

...