vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.99k stars 33.69k forks source link

SSR with webpack5, run renderToString() report "cannot find module ''../js/xxx.js" when use import() to lazy load components in router configs. #12924

Open YataoZhang opened 1 year ago

YataoZhang commented 1 year ago

Version

2.7.14

Reproduction link

github.com

Steps to reproduce

step 1: write a simple vue-router use cases:

import Vue from 'vue';
import VueRouter from "vue-router";

Vue.use(VueRouter);

export default function () {
    const router = new VueRouter({
        mode: 'history',
        base: '/',
        routes: [
            {
                path: '/',
                redirect: '/index'
            }, {
                path: '/index',
                component: () => import(
                    /* webpackChunkName: "index" */
                    '@/pages/index.vue'
                )
            }, {
                path: '/about',
                component: () => import(
                    /* webpackChunkName: "about" */
                    '@/pages/about.vue'
                )
            }],
    });
    return router;
}

Step 2: configuration vue.config.js for server bundle of SSR Mode:

const { defineConfig } = require('@vue/cli-service')
const nodeExternals = require('webpack-node-externals');
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');

module.exports = defineConfig({
  productionSourceMap: false,
  css: {
    extract: false,
  },
  transpileDependencies: true,
  configureWebpack: {
    entry: '@/enter-server.js',
    target: 'node',
    output: {
      library: {
        type: 'commonjs2'
      },
      libraryTarget: 'commonjs2',
    },
    externals: nodeExternals({
      allowlist: [/\.css$/],
    }),
    optimization: {
      splitChunks: { chunks: 'all' },
    },
    plugins: [
      new VueSSRServerPlugin(),
    ],
  }
})

Step 3: write a render test case:

const { createBundleRenderer } = require('vue-server-renderer');
const serverBundle = require('./dist/vue-ssr-server-bundle.json');
const createRenderer = (bundle, options = {}) => {
    return createBundleRenderer(bundle, Object.assign(options, {
        runInNewContext: false
    }));
};
let renderer = createRenderer(serverBundle);
const ctx = {
    route: { path: '/index' },
};
renderer.renderToString(ctx, (err, html) => {
    if (err) {
        return console.log(err);
    }
    console.log(html);
});

What is expected?

run command: npm run build, and it will emit some errors:

[vue-router] Failed to resolve async component default: Error: Cannot find module '../js/index.5c9c2de1.js'

What is actually happening?

In Webpack5, when the output.target is "node". it will use the installChunk(require("../" + __webpack_require__.u(chunkId))); to load the all async modules. and "vue-server-renderer/server-plugin" will put all modules in .json file.

The reason it on the "../". while renderToString() was executed. cause cannot resolve and async components bundle with prefix ”.../“ in evaluateModule().


finally, i am apologize for my pool english.

WinfredWang commented 1 year ago

same issue

ReySun commented 1 year ago

try add specific filename to webpack.output, like this:

output: {
      libraryTarget: "commonjs2",
      filename: "server-bundle.js",
}