Using Spectron to "mock" Electron when testing with Jest - jestjs

I'm testing library code for an Electron app with Jest. Jest does weird things to require, which is interfering with that Electron needs to do... I think.
Spectron is meant to allow you to access the various Electron bits from within a test framework, by allowing you to create an Electron app via library calls.
Ultimately, I need to be able to mock require('electron') with some real stuff from Electron (like the creation of browser windows), mostly so that various library bits can work as intended.
Here's what it looks like should work:
in package.json:
"jest": {
"moduleNameMapper": {
"^electron$": "<rootDir>/test/mocks/electron.js"
}
}
test/mocks/electron.js:
const Path = require("path")
const Application = require('spectron').Application
const electronPath = Path.join(__dirname, "../../node_modules/electron/dist/Electron.app/Contents/MacOS/Electron")
const app = new Application({ path: electronPath })
module.exports = app.electron
According to the docs, app.electron should give access to the same things as require('electron') does under normal operation.
Some test:
const { BrowserWindow } = require("electron")
test("some test", () => {
const window = new BrowserWindow()
// ...
})
However, this fails because app.electron is undefined, although App itself is defined:
console.log test/mocks/electron.js:58
<ref *1> Application {
host: '127.0.0.1',
port: 9515,
quitTimeout: 1000,
startTimeout: 5000,
waitTimeout: 5000,
connectionRetryCount: 10,
connectionRetryTimeout: 30000,
nodePath: '~/.nvm/versions/node/v13.0.1/bin/node',
path: '~/electron-hello-world/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron',
args: [],
chromeDriverArgs: [],
env: {},
workingDirectory: '~/electron-hello-world',
debuggerAddress: undefined,
chromeDriverLogPath: undefined,
webdriverLogPath: undefined,
webdriverOptions: {},
requireName: 'require',
api: Api { app: [Circular *1], requireName: 'require' },
transferPromiseness: [Function (anonymous)]
}
Not really sure where to go from here. Looking for any solutions

Related

Astro: How to proxy service calls

I am setting up an Astro site which will display data fetched from a simple service running on the same host but a different port.
The service is a simple Express app.
server.js:
const express = require('express')
const app = express()
const port = 3010
const response = {
message: "hello"
}
app.get('/api/all', (_req, res) => {
res.send(JSON.stringify(response))
})
app.listen(port, () => {
console.log(`listening on port ${port}`)
})
Since the service is running on port 3010, which is different from the Astro site, I configure a server proxy at the Vite level.
astro.config.mjs:
import { defineConfig } from 'astro/config';
import react from '#astrojs/react';
export default defineConfig({
integrations: [react()],
vite: {
optimizeDeps: {
esbuildOptions: {
define: {
global: 'globalThis'
}
}
},
server: {
proxy: {
'/api/all': 'http://localhost:3010'
}
}
},
});
Here is where I am trying to invoke the service.
index.astro:
---
const response = await fetch('/api/all');
const data = await response.json();
console.log(data);
---
When I run yarn dev I get this console output:
Response {
size: 0,
[Symbol(Body internals)]: {
body: Readable {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
_read: [Function (anonymous)],
[Symbol(kCapture)]: false
},
stream: Readable {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
_read: [Function (anonymous)],
[Symbol(kCapture)]: false
},
boundary: null,
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
type: 'default',
url: undefined,
status: 404,
statusText: '',
headers: { date: 'Tue, 02 Aug 2022 19:41:02 GMT' },
counter: undefined,
highWaterMark: undefined
}
}
It looks like the network request is returning a 404.
I'm not seeing in the doc much more about server configuration.
Am I going about this the right way?
I have this working correctly with a vanilla Vite app and the same config/setup.
How can I proxy local service calls for an Astro application?
Short Answer
You cannot proxy service calls with Astro but also you don't have to
For direct resolution answer see section functional test without proxy
Details
Astro does not forward the server.proxy config to Vite (unless you patch your own version of Astro), the Astro Vite server config can be seen empty
proxy: {
// add proxies here
},
reference https://github.com/withastro/astro/blob/8c100a6fe6cc652c3799d1622e12c2c969f30510/packages/astro/src/core/create-vite.ts#L125
there is a merge of Astro server with Astro vite.server config but it does not take the proxy param. This is not obvious to get from the code, see tests later.
let result = commonConfig;
result = vite.mergeConfig(result, settings.config.vite || {});
result = vite.mergeConfig(result, commandConfig);
reference https://github.com/withastro/astro/blob/8c100a6fe6cc652c3799d1622e12c2c969f30510/packages/astro/src/core/create-vite.ts#L167
Tests
Config tests
I tried all possible combinations of how to input config to Astro and in each location a different port number to show which one takes an override
a vite.config.js file on root with
export default {
server: {
port:6000,
proxy: {
'/api': 'http://localhost:4000'
}
}
}
in two locations in the root file astro.config.mjs
server
vite.server
export default defineConfig({
server:{
port: 3000,
proxy: {
'/api': 'http://localhost:4000'
}
},
integrations: [int_test()],
vite: {
optimizeDeps: {
esbuildOptions: {
define: {
global: 'globalThis'
}
}
},
server: {
port:5000,
proxy: {
'/api': 'http://localhost:4000'
}
}
}
});
in an Astro integration
Astro has a so called integration that helps update the config (sort of Astro plugins) the integration helps identify what was finally kept in the config and also gives a last chance to update the config
integration-test.js
async function config_setup({ updateConfig, config, addPageExtension, command }) {
green_log(`astro:config:setup> running (${command})`)
updateConfig({
server:{proxy : {'/api': 'http://localhost:4000'}},
vite:{server:{proxy : {'/api': 'http://localhost:4000'}}}
})
console.log(config.server)
console.log(config.vite)
green_log(`astro:config:setup> end`)
}
this is the output log
astro:config:setup> running (dev)
{ host: false, port: 3000, streaming: true }
{
optimizeDeps: { esbuildOptions: { define: [Object] } },
server: { port: 5000, proxy: { '/api': 'http://localhost:4000' } }
}
astro:config:setup> end
the proxy parameter is removed from astro server config, the vite config is visible but has no effect as it is overridden, and not forwarded to Vite
test results
dev server runs on port 3000 which is from Astro config server all other configs overridden
the fetch api fails with the error
error Failed to parse URL from /api
File:
D:\dev\astro\astro-examples\24_api-proxy\D:\dev\astro\astro-examples\24_api-proxy\src\pages\index.astro:15:20
Stacktrace:
TypeError: Failed to parse URL from /api
at Object.fetch (node:internal/deps/undici/undici:11118:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
functional test without proxy
Given that Astro front matter runs on the server side, in SSG mode during build and in SSR mode on page load on the server then the server sends the result html, Astro has access to all host ports and can directly use the service port like this
const response = await fetch('http://localhost:4000/api');
const data = await response.json();
console.log(data);
The code above runs as expected without errors
Reference Example
All tests and files mentioned above are available on the reference example github repo : https://github.com/MicroWebStacks/astro-examples/tree/main/24_api-proxy
You can add your own proxy middleware with the astro:server:setup hook.
For example use http-proxy-middleware in the server setup hook.
// plugins/proxy-middleware.mjs
import { createProxyMiddleware } from "http-proxy-middleware"
export default (context, options) => {
const apiProxy = createProxyMiddleware(context, options)
return {
name: 'proxy',
hooks: {
'astro:server:setup': ({ server }) => {
server.middlewares.use(apiProxy)
}
}
}
}
Usage:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import proxyMiddleware from './plugins/proxy-middleware.mjs';
// https://astro.build/config
export default defineConfig({
integrations: [
proxyMiddleware("/api/all", {
target: "http://localhost:3010",
changeOrigin: true,
}),
],
});

Jest+NextJs: You should only use "next/router" on the client side of your app

I'm mocking the next/router dependency in my Jest+React-testing-libray tests as I always have:
import * as nextRouter from 'next/router';
export const routerData = {
pathname: '/users/create',
route: '/users/create',
query: { },
asPath: '/users/create',
isFallback: false,
basePath: '',
isReady: true,
isPreview: false,
isLocaleDomain: false,
events: {},
};
// mock router
jest.mock('next/router');
nextRouter.useRouter.mockImplementation(() => (routerData));
describe('a component that requires next/router, () => ... );
This had been working correctly but after updating to NextJs 12.2.0 I get this warning:
No router instance found.
You should only use "next/router" on the client side of your app.
This warning makes all my tests with the mocked router to fail.
Ideas to fix this?
Well, it appears that this is not related to 12.2.0. Somehow my last version of Next - 12.0.0 - wasn't thrownig this error but other older versions did.
Thanks to bistacos for the response here.
const useRouter = jest.spyOn(require('next/router'), 'useRouter');
useRouter.mockImplementation(() => ({
pathname: '/',
...moreRouterData
}));

Koa 404 when calling from Vue

I am trying to build an app with Koa and Nuxt. this is what I have:
Define service to retrieve from firestore:
const Firestore = require('#google-cloud/firestore');
const getItems = () => {
const db = new Firestore({
projectId: '*******',
keyFilename: "******"
});
db.collection('items').get()
.then((snapshot) => {
return snapshot;
})
}
Define them in routes.js:
const Router = require('#koa/router');
const articleService = require('./services/itemservice');
const router = new Router();
router.get('/getitems', async(ctx, next) => {
ctx.body = articleService.getItems();
});
module.exports = router;
Add routes to retrieve from routes.js:
app.use(router.routes());
app.use(router.allowedMethods());
And finally call it from a component:
let articles = axios.get('/getitems')
.then(response => {
console.log(response);
})//.....
I am receiving this error:
response:
{ status: 404,
statusText: 'Not Found',
headers:
{ 'content-type': 'text/html; charset=us-ascii',
server: 'Microsoft-HTTPAPI/2.0',
date: 'Fri, 25 Oct 2019 16:08:00 GMT',
connection: 'close',
'content-length': '315' },
config:
{ url: '/getarticles',
method: 'get',
headers: [Object],
transformRequest: [Array],
transformResponse: [Array],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
data: undefined },
request:
ClientRequest {
_header:
'GET /getitems HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nUser-Agent: axios/0.19.0\r\nHost: localhost\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
timeout: undefined,
method: 'GET',
path: '/getitems',
_ended: true,
res: [IncomingMessage],
aborted: undefined,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
_redirectable: [Writable],
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]: [Object] },
data:
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">\r\n<HTML><HEAD><TITLE>Not Found</TITLE>\r\n<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>\r\n<BODY><h2>Not Found</h2>\r\n<hr><p>HTTP Error 404. The requested resource is not found.</p>\r\n</BODY></HTML>\r\n' },
isAxiosError: true,
toJSON: [Function] }
Can anyone point me in the right direction?
I've never built an app with Nuxt, but I'll try to help you anyway.
First, I recommend you to read about Promises:
- https://github.com/leonardomso/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch3.md
- https://github.com/leonardomso/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch8.md
(those are two chapters of a good JS book series!)
Second, you can try two things in order to find the bug:
- add a .catch block to your thenables, to check if something went wrong;
- add a dummy route that just logs an 'OK', to make sure the routes are be registered and up to respond.
I hope this will help you!
I had this problem with my nuxt / express.js app:
If you would try to type in your browser yourURL/getitems your nuxt app will try to route you to that page instead of just to show u the data.
First thing to do, how to say, you need to define what url your backend should handle.
You go to your nuxt.config.js and add this line of code:
serverMiddleware: ["~/api/index.js"],
That means you have a folder called api and in that folder you have an index.js file and thats your express.js / koa app.
Now in your index.js where your express.js / koa app is you need to add at the end of the line this peace of code:
module.exports = {
path: "/api",
handler: app
};
If everything works fine your URL should have now a prefix api and you should be able to get the data with localhost:PORT/api/getitems
Now nuxt wont try to route you to your url/api because it knows now that this is your backend
If you could provide me your folder structure of your nuxt app i could help you more.
Here is more information about serverMiddleware
https://nuxtjs.org/api/configuration-servermiddleware
EDIT:
somewhere you have a Folder, lets say ist named server or api
in that Folder there should be a index.js file and your routes, model, Controllers etc.
Lets say you have a Folder called server and in that Server you have index.js that should look something like this
const Koa = require('koa');
const app = new Koa();
Import routes from "./routes.js"
app.use(routes)
//here you define now your backend path
module.exports = {
//you can use any path you want
path: "/backend",
handler: app
};
app.listen(3000);
Now you Need to go to your nuxt.config.js file and Point to that index.js File
serverMiddleware: ["~/server/index.js"]
Now you can Access your data with axios:
axios.get("/backend/getitems").then(data => { console.log(data) })
You will Need to add backend to your axios url because thats the path you defined that your Server will handle.

Webpacking a NodeJS Express API with MySQL throws connection error in mode '-p', not in '-d'

I have a simple Express API where I use MySQL to retrieve my data. I use Webpack 4 to bundle it with a very simple configuration:
'use strict';
const path = require('path');
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
};
When I use webpack --config webpack.config.js -d for development everything works just fine.
However, when I run webpack --config webpack.config.js -p for production it suddenly doesn't work anymore, and throws an error when it's getting a connection from the pool.
TypeError: Cannot read property 'query' of undefined
at Object.getItem (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154359)
at t.db_pool.getConnection (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154841)
at c._callback (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:68269)
at c.end (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:8397)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322509
at Array.forEach (<anonymous>)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322487
at process._tickCallback (internal/process/next_tick.js:112:11)
So somehow this is broken by using the production mode in webpack 4. The connection object undefined somehow, while it isn't in development mode.
I have no idea how to fix this, since I'm a noob in using Webpack. I tried searching on google, but couldn't find anything relevant.
How I create my pool:
'use strict';
var mysql = require('mysql');
var secret = require('./db-secret');
module.exports = {
name: 'gept_api',
hostname: 'https://api.toxsickproductions.com/gept',
version: '1.3.0',
port: process.env.PORT || 1910,
db_pool: mysql.createPool({
host: secret.host,
port: secret.port,
user: secret.user,
password: secret.password,
database: secret.database,
ca: secret.ca,
}),
};
How I consume the connection:
pool.getConnection((err, connection) => {
PlayerRepository.getPlayer(req.params.username, connection, (statusCode, player) => {
connection.release();
res.status(statusCode);
res.send(player);
return next();
});
});
and
/** Get the player, and logs to HiscoreSearch if exists.
*
* Has callback with statusCode and player. Status code can be 200, 404 or 500.
* #param {string} username The player's username.
* #param {connection} connection The mysql connection object.
* #param {(statusCode: number, player: { username: string, playerType: string }) => void} callback Callback with statusCode and the player if found.
*/
function getPlayer(username, connection, callback) {
const query = 'SELECT p.*, pt.type FROM Player p JOIN PlayerType pt ON p.playerType = pt.id WHERE username = ?';
connection.query(query, [username.toLowerCase()], (outerError, results, fields) => {
if (outerError) callback(500);
else if (results && results.length > 0) {
logHiscoreSearch(results[0].id, connection, innerError => {
if (innerError) callback(500);
else callback(200, {
username: results[0].username,
playerType: results[0].type,
deIroned: results[0].deIroned,
dead: results[0].dead,
lastChecked: results[0].lastChecked,
});
});
} else callback(404);
});
}
I found what was causing the issue. Apparantly the mysql package relies on Function.prototype.name because setting keep_fnames: true fixed the production build. (https://github.com/mishoo/UglifyJS2/tree/harmony#mangle-options)
I disabled the Webpack 4 standard minification and used custom UglifyJSPlugin settings:
'use strict';
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
optimization: {
minimize: false,
},
plugins: [
new UglifyJsPlugin({
parallel: true,
uglifyOptions: {
ecma: 6,
mangle: {
keep_fnames: true,
},
},
}),
],
};

How to structure a Vue 2.0 app for server-rendered lazy routes?

I attempted to modify vue-hackernews-2.0 to support lazy-loaded routes using Webpack's code-splitting feature as per instructions found at these links:
https://router.vuejs.org/en/advanced/lazy-loading.html
http://vuejs.org/guide/components.html#Async-Components
However, I ran into some issues. When I loaded the app in the browser, all suggested variations of syntax triggered Module not found errors on the server-side when attempting to load in the server-side chunks.
Given this wrapper around the code-split points in router.js...
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
// INSERT CODE-SPLIT POINT SYNTAXES HERE (they are below)
export default new Router({
mode: 'history',
routes: [{
path: '/',
component: Home
}, {
path: '/foo',
component: Foo
}]
})
All of these variations of syntax threw the Module not found error:
Variation 1:
const Home = () => System.import('./views/Home.vue')
const Foo = () => System.import('./views/Foo.vue')
Variation 2:
const Home = (resolve) => require(['./views/Home.vue'], resolve)
const Foo = (resolve) => require(['./views/Foo.vue'], resolve)
Variation 3:
const Home = (resolve) => {
require.ensure(['./views/Home.vue'], () => {
resolve(require('./views/Home.vue'))
})
}
const Foo = (resolve) => {
require.ensure(['./views/Foo.vue'], () => {
resolve(require('./views/Foo.vue'))
})
}
The error message was always along the lines of:
(note: this error is adapted from a small reproduction I made of the issue, not from the hackernews example)
Error: Cannot find module './0.server.js'
at Function.Module._resolveFilename (module.js:440:15)
at Function.Module._load (module.js:388:25)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
at Function.requireEnsure [as e] (__vue_ssr_bundle__:42:25)
at Home (__vue_ssr_bundle__:152:30)
at /Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1421:19
at iterator (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1277:5)
at step (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1213:9)
at step (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1217:9)
I tried adapting my code to use the suggestions offered at Server-side react with webpack 2 System.import, but those did not work either.
I read a post that described configuring a build-time global variable using Webpack's DefinePlugin that allowed me to inspect whether the code was running on the server or on the client - this allows me to code-split on the client, but just bundle everything in on the server.
In the server webpack config:
{
...
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: false
})
]
...
}
In the client webpack config:
{
...
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: true
})
]
...
}
Then, in the same wrapper-snippet as above for the router.js file, I used this variation of syntax:
const Home = BROWSER_BUILD ? () => System.import('./views/Home.vue') : require('./views/Home.vue')
const Foo = BROWSER_BUILD ? () => System.import('./views/Foo.vue') : require('./views/Foo.vue')
This made rendering work - partially. Navigating directly to the app in the browser (and respective routes) server-rendered the correct UI. Clicking around, vue-router's client-side logic took me to the right UI. Everything seemed hunky-dory - until I opened DevTools:
The same issue also occurs if a module is loaded lazily as a subcomponent of a route:
<template>
<div class="page">
<heading></heading>
</div>
</template>
<script>
const Heading = BROWSER_BUILD ? () => System.import('./Heading.vue') : require('./Heading.vue')
export default {
components: {
Heading
}
}
</script>
I tried asking for some help in the official Vue forum, but came up empty: http://forum.vuejs.org/t/2-0-help-needed-with-server-rendered-lazy-routes/906
Thinking this might be a bug with vue-router, I opened an issue there: https://github.com/vuejs/vue-router/issues/820
Unfortunately, I wasn't able to find a solution.
So, I put together a small repo that reproduces the issue: https://github.com/declandewet/vue2-ssr-lazy-error
I have a hunch that the actual problem might be coming from https://www.npmjs.com/package/vue-server-renderer.
I'm really stuck on this and am used to how easy it is to do in react - and would really appreciate any help/tips/direction towards a solution!
Here is the webpack config from the reproduction repo for convenience:
import fs from 'fs'
import path from 'path'
import webpack from 'webpack'
import validate from 'webpack2-validator'
import { dependencies } from './package.json'
let babelConfig = JSON.parse(fs.readFileSync('./.babelrc'))
/* turn off modules in es2015 preset to enable tree-shaking
(this is on in babelrc because setting it otherwise causes issues with
this config file) */
babelConfig.presets = babelConfig.presets.map(
(preset) => preset === 'es2015' ? ['es2015', { modules: false }] : preset
)
const babelOpts = {
...babelConfig,
babelrc: false,
cacheDirectory: 'babel_cache'
}
const SHARED_CONFIG = {
devtool: 'source-map',
module: {
loaders: [{
test: /\.vue$/,
loader: 'vue'
}, {
test: /\.js$/,
loader: 'babel',
exclude: 'node_modules',
query: babelOpts
}]
},
resolve: {
modules: [
path.join(__dirname, './src'),
'node_modules'
]
}
}
const SERVER_CONFIG = validate({
...SHARED_CONFIG,
target: 'node',
entry: {
server: './src/server.js',
renderer: './src/renderer.js'
},
output: {
path: path.join(__dirname, './dist'),
filename: '[name].js',
chunkFilename: '[id].server.js',
libraryTarget: 'commonjs2'
},
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: false,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
new webpack.BannerPlugin({
banner: 'require("source-map-support").install();',
raw: true,
entryOnly: false
})
],
externals: Object.keys(dependencies)
})
const CLIENT_CONFIG = validate({
...SHARED_CONFIG,
entry: {
app: './src/client.js',
vendor: ['vue']
},
output: {
path: path.join(__dirname, './dist/assets'),
publicPath: '/',
filename: 'bundle.js'
},
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: true,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js'
})
]
})
export default [SERVER_CONFIG, CLIENT_CONFIG]
EDIT: Noticing that in React, we use match on the client to get the right route config for the current view, I decided to inspect what components were getting matched using app.$router.getMatchedComponents() and found something interesting:
Server Entry:
import app from './app'
export default (context) => {
// using app.$router instead of importing router itself works
// (not sure why the hacker-news example imports the router module instead...)
app.$router.push(context.url)
const components = app.$router.getMatchedComponents()
console.log('server-side', components)
return Promise.all(components.map((component) => component))
.then(() => app)
}
When navigating to the home page, this logs to the terminal:
server-side [ { __file: '/Users/razorbeard/projects/vue-2-ssr/src/views/Home.vue',
render: [Function],
staticRenderFns: [ [Function] ] } ]
Client Entry:
import app from './app'
const components = app.$router.getMatchedComponents()
console.log('client-side', components)
// kickoff client-side hydration
Promise.all(components.map((component) => Promise.resolve(component)))
.then(() => app.$mount('#app'))
When navigating to the home page, this logs to the devtools console:
client-side []
As you can see, no components are getting matched on the client side.

Resources