延迟加载的 vue-router 组件不适用于 s-s-r

Posted

技术标签:

【中文标题】延迟加载的 vue-router 组件不适用于 s-s-r【英文标题】:Lazy-Loaded vue-router components don't work with s-s-r 【发布时间】:2020-02-01 15:28:39 【问题描述】:

我有两个不同的 server.js 和 client.js 入口点。(我正在使用 vue-server-renderer 和 laravel-mix)-(我的 server.js 和 client.js 看起来与此处描述的完全一样-@ 987654321@ 如果我进行静态导出 import Test from '../views/Test' 它可以工作..

如果我尝试在不延迟加载的情况下导入路由,s-s-r 可以:

import Test from "../views/Test";

export const routes = [
    path: '/my-route',
    name: "Test",  
    component: Test,
]

但如果我尝试延迟加载,它会在 s-s-r 上失败:

export const routes = [
    path: '/my-route',
    name: "Test"
    component: () => import('../views/Test.vue'),
]

找不到模块'./js/chunks/server/0.js?id=c3384f174123f0848451'

对于() => import('../views/Home.vue),client.js 有效,只有 server.js 无效。


我的server.js

import renderVueComponentToString from 'vue-server-renderer/basic';
import app from './app';
import router from './router/index';

new Promise((resolve, reject) => 
    router.push(context.url);
    router.onReady(() => 
        resolve(app);
    , reject);
)
    .then(app => 
        renderVueComponentToString(app, (err, res) => 
            if (err) throw new Error(err);

            dispatch(res);
        );
    );

完整的错误是:

命令“/usr/bin/node /home/vagrant/Code/project/storage/app/s-s-r/1228cfee3f79dc5949bd898950384e53.js”失败退出代码:1(一般错误)

工作目录:/home/vagrant/Code/project/public 输出:

================ 错误输出:================ internal/modules/cjs/loader.js:628 throw呃; ^

错误:找不到模块'./js/chunks/server/0.js?id=c3384f174123f0848451'


更新

我想我可能知道为什么会发生这种情况(我可能错了):

export const routes = [
     path: '/', 
     name: "Home", 
     component: () => import('../views/Home')
]

使用此代码,我得到一个错误:

错误:找不到模块'./js/chunks/server/0.js?id=c3384f174123f0848451'

命令“/usr/bin/node /home/vagrant/Code/project/storage/app/s-s-r/717358e60bfd52035a1e58256cdfbba0.js”失败。退出代码:1(一般错误)工作目录:/home/vagrant/Code/project/public 输出:================ 错误输出:======== ======== internal/modules/cjs/loader.js:628 throw err; ^ 错误:找不到模块 './js/chunks/server/0.js?id=c3384f174123f0848451'

查看路径: 在我编译的文件中(位于public/js)我有这一行:

var chunk = require("./js/chunks/server/" + ([chunkId]||chunkId) + ".js?id=" + "0":"c3384f174123f0848451"[chunkId] + "");

这似乎是一个相对路径。但是,该文件实际上是在我在 config/s-s-r.php - 'temp_path' => storage_path('app/s-s-r') 中指定的文件中运行的 - 所以它找不到路径。

但是,即使我将temp_path 更改为public_path() 以便它可以从./js/chunks/server/(即public/js/chunks/server/0.js)中找到块,它仍然会抛出相同的错误。即使 s-s-r 的 temp_path 不同。

命令“/usr/bin/node /home/vagrant/Code/project/public/3560d8d101faa4bdef316054b14873cc.js”失败。退出代码:1(一般错误)工作目录:/home/vagrant/Code/project/public 输出:================ 错误输出:======== ======== internal/modules/cjs/loader.js:628 throw err; ^ 错误:找不到模块 './js/chunks/server/0.js?id=c3384f174123f0848451'

另外,如果我在renderVueComponentToString()console.log(_dirname) 它返回我'/'

【问题讨论】:

【参考方案1】:

我解决了,现在它只能在客户端与 s-s-r 和代码拆分一起使用 - 如果您有更好的想法,我仍然全神贯注。

我使用了spatie/laravel-server-side-rendering,它很容易设置。

这是我的解决方案(以及我对 spatie/laravel-server-side-rendering 的更改):

我了解了如何从 charlesBochet's comment 中分离包,但是我使用了一个而不是 2 个 webpack.mix.js 文件。

package.json
"scripts": 
    // concurrently is just for building them asynchronously 
    "dev-all": "concurrently \"npm --section=server run dev\" \"npm --section=client run dev\"  --kill-others-on-fail",

    // can also build them separately if you wish
    "dev-client": "npm --section=client run dev",
    "dev-server": "npm --section=server run dev"
     ...

webpack.mix.js
if (process.env.npm_config_section === 'server') 
    mix.js('resources/js/app-server.js', 'public/js')
        .webpackConfig(
            target: 'node',

            // Prevent code-splitting for server-build
            plugins: [
                new webpack.optimize.LimitChunkCountPlugin(
                    maxChunks: 1,
                )
            ],
        )
        // merge manifest is a package for merging manifests,
        // otherwise they'll get overwritten by each other
        // https://github.com/kabbouchi/laravel-mix-merge-manifest
        .mergeManifest()
        .version();

 else if (process.env.npm_config_section === 'client') 
    mix.js('resources/js/app-client.js', 'public/js')
        .webpackConfig(
            target: 'web',
            output: 
                chunkFilename: 'js/chunks/[name].js?id=[chunkhash]',
                publicPath: '/',
            ,
        )
        .mergeManifest()
        .version();

    // Only build css with the client build, server build only needs
    // the html and not the css
    mix.sass('resources/sass/app.scss', 'public/css')
 else 
    console.log(
        '\x1b[41m%s\x1b[0m',
        'Provide correct --section argument to build command: server, client'
    );
    throw new Error('Provide correct --section argument to build command!')

app-server.js - 应该等待路由器准备好
new Promise((resolve, reject) => 
    router.push(context.url);
    router.onReady(() => 
        resolve(app);
    , reject);
)
    .then(app => 
        renderVueComponentToString(app, (err, res) => 
            if (err) throw new Error(err);
            dispatch(res);
        );
    );
app-client.js
router.onReady(function() 
    app.$mount('#app');
)
最后路由器文件代码分割适用于 app-client.js
export const routes = [

    path: '/',
    name: "Home",
    component: () => import('../views/Home.vue')
,

【讨论】:

【参考方案2】:

不确定问题出在哪里,但您应该阅读以下内容:

请注意,在返回/挂载应用程序之前,仍然需要在服务器和客户端上都使用 router.onReady,因为路由器必须提前解析异步路由组件才能正确调用-组件挂钩...Vue s-s-r, Routing and Code-Splitting

所以不是

app.$mount('#app');

试试

router.onReady(() => 
  app.$mount('#app')
)

希望这会有所帮助。

【讨论】:

我明白你的意思,我在 OP 中添加了我的 server.js 代码。但它返回给我Cannot find module './js/chunks/server/0.js?id=c3384f174123f0848451' - (顺便说一句,你的代码是用于客户端入口而不是服务器入口,我的问题是在服务器入口;客户端入口工作正常) 嘿伙计!实际上,您将我引向了正确的方向。为此非常感谢!如果你想看看,我已经发布了完整的解决方案 很高兴它有帮助...刚开始一个 VUE s-s-r 项目,从您的经验中学到了很多

以上是关于延迟加载的 vue-router 组件不适用于 s-s-r的主要内容,如果未能解决你的问题,请参考以下文章

Angular <custom-component> 不适用于延迟加载的模块

Vue 2 应用程序无法在 vue-router 中延迟加载路由导入组件

React 中的延迟加载 util 函数

休眠延迟加载不适用于多对一映射

休眠延迟加载不适用于 Spring Boot => 无法延迟初始化角色集合无法初始化代理 - 无会话

Spring boot JPA - 延迟加载不适用于一对一映射