Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bundleRenderer fails when the application and the vue-server-renderer are in different modules/packages #4936

Closed
sinisterstumble opened this issue Feb 15, 2017 · 14 comments

Comments

@sinisterstumble
Copy link

sinisterstumble commented Feb 15, 2017

This is my first issue, so before anything else - thanks to @yyx990803 and Vue community for awesome work!

Vue.js version

2.0.2

Reproduction Link

https://github.com/abc/vueSSRTest

Steps to reproduce

This works as expected

$ git clone https://github.com/abc/vueSSRTest.git
$ cd vueSSRTest/app
$ npm install
$ node bundleRenderer.js
<div id="hello" server-rendered="true">heloo</div>

This fails

$ cd vueSSRTest/renderer
$ npm install
$ node bundleRenderer.js
(node:24852) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Cannot find module 'vue'  
(node:24852) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

What is Expected?

vue-server-renderer's bundleRenderer is expected to execute the pre-bundled application successfully, even when the application is in a separate module/package.

What is actually happening?

vue-server-renderer's bundleRenderer fails to execute the pre-bundled application when the application and the vue-server-renderer are in different packages.

@sinisterstumble
Copy link
Author

sinisterstumble commented Feb 15, 2017

This is a reply to a removed comment, that suggested not externalizing dependencies.


That's correct, see vue-server-renderer README.md

When using the bundleRenderer, we will by default bundle every dependency of our app into the server bundle as well. This means on each request these depdencies will need to be parsed and evaluated again, which is unnecessary in most cases.

We can optimize this by externalizing dependencies from your bundle. During the render, any raw require() calls found in the bundle will return the actual Node module from your rendering process. With Webpack, we can simply list the modules we want to externalize using the externals config option:

@LinusBorg
Copy link
Member

LinusBorg commented Feb 15, 2017

I don't exactly understand what you are expecting ... How should you app know that the dependencies of the server bundle that you loaded should not be looked up in the local /node_modules/ directory, but the one where we loaded the bundle from?

@sinisterstumble
Copy link
Author

@LinusBorg my expectation is that vue-server-renderer would look up the application dependencies in the application node_modules. The current behavior is vue-server-renderer looks for the application dependencies in it's own node_modules.

@LinusBorg
Copy link
Member

LinusBorg commented Feb 15, 2017

createBundleRenderer(code, [rendererOptions])
Creates a bundleRenderer instance using pre-bundled application code

(emphasis mine)
You have to build the server bundle in /app, and then load that bundled .js file in /renderer

You currently don't bundle anything, and instead simply require the unbundled code as if it was a normal commonjs module for node. Even if you would get it to require from the other node_modules directory, all fo this would fail once your code refers to a .vue file (or anything other than a normal .js file), or an import statement, which node doesn't understand, either. You have to pre-bundle with webpack.

@sinisterstumble
Copy link
Author

Not really, if you take a look at app/lib/server-bundle.js - it's bundled with webpack. The webpack configuration is also in the repository app/webpack.config.js and you can re-bundle by running npm run build or just webpack

@sinisterstumble
Copy link
Author

@LinusBorg can you reproduce the issue ?

@yyx990803
Copy link
Member

This is expected behavior. First because of the externals config, the app's dependencies like vue are not bundled into the server bundle. They will be loaded dynamically at runtime. However, the server-renderer can only load dependencies from where itself is installed. This means it needs to be in the same node_modules tree with your app's dependencies.

Is there any particular reason you have to structure your project this way?

@LinusBorg
Copy link
Member

Ah! Sorry.

But, you excluded all dependencies, which brings us back to my original point, to which you replied:

my expectation is that vue-server-renderer would look up the application dependencies in the application node_modules.

Well, for that, node /which will require the dependencies that you externalized during build of the bundle) has to know about that path.

https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders

@sinisterstumble
Copy link
Author

This has nothing to do with global folders, the typical node behavior is that module is not actually a global but rather local to each module. That is illustrated by running node app/lib/server-bundle.js for anywhere outside of the app directory, it won't throw an error and will successfully require vue and the externalized dependencies. This is exactly the expected behavior from vue-server-renderer. The issue here is (somewhere in this file) bundleRenderer creates a vm sandbox and injects node globals, which are not really global but rather local.

@sinisterstumble
Copy link
Author

@yyx990803 the typical use case is decoupling the web server (with ssr) from the application. One dirty workaround, is monkey patching the NativeModule.prototype.require, but I was hoping for a cleaner fix.

@LinusBorg
Copy link
Member

I was linking to the section about global modules for NODE_PATH as a possible workaround/solution.

@sinisterstumble
Copy link
Author

Added the NativeModule.prototype.require workaround to the repository.

Maybe something like node-resolve in the sandbox ?

@sinisterstumble
Copy link
Author

@yyx990803 thank you!

@dbl520
Copy link

dbl520 commented Mar 17, 2021

我将有关NODE_PATH的全球模块作为可能的解决方法/解决方案链接到该部分。

node_path环境变量配好就行了?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants