Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,8 @@ module.exports = class Response extends Writable {
this.send(str);
});

this.app.render(view, options, done);
// use req.app like express does, so mounted sub-apps resolve views with their own settings
this.req.app.render(view, options, done);
}
cookie(name, value, options) {
const opt = {...(options ?? {})}; // create a new ref because we change original object (https://github.com/dimdenGD/ultimate-express/issues/68)
Expand Down
10 changes: 9 additions & 1 deletion src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ module.exports = class Router extends EventEmitter {
[...chainPrefix, ...pathToMount, {
...route,
callbacks: [],
keepMount: true
keepMount: true,
// mounted sub-apps become req.app during their dispatch, like express
mountApp: route.callbacks[0].constructor.name === 'Application' ? route.callbacks[0] : undefined
}]
);
}
Expand Down Expand Up @@ -495,6 +497,7 @@ module.exports = class Router extends EventEmitter {
return false;
}
// on optimized routes, there can be more routes, so we have to use unoptimized routing and skip until we find route we stopped at
req.app = this; // restore app in case the optimized path swapped it to a mounted sub-app
return this._routeRequest(req, res, 0, this._routes, false, skipUntil);
}
let callbackindex = 0;
Expand All @@ -507,6 +510,11 @@ module.exports = class Router extends EventEmitter {

const strictRouting = this.get('strict routing');
if(route.use) {
if(route.mountApp) {
// optimized chain: normal dispatch swaps req.app when it enters a mounted Application,
// but the compiled mount route has no callback to do it, so swap it here
req.app = route.mountApp;
}
req._stack.push(route.path);
const fullMountpath = this.getFullMountpath(req);
req._opPath = fullMountpath !== EMPTY_REGEX ? req._originalPath.replace(fullMountpath, '') : req._originalPath;
Expand Down
2 changes: 2 additions & 0 deletions tests/parts/subapp/index.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1>subapp <%= message %></h1>
<span><%= asdf %></span>
50 changes: 50 additions & 0 deletions tests/tests/res/res-render-subapp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// res.render must use the views and engine of the sub-app handling the request

const express = require("express");

const app = express();
app.set('view engine', 'ejs');
app.set('views', 'tests/parts');
app.set('env', 'production');

const subApp = express();
subApp.set('view engine', 'ejs');
subApp.set('views', 'tests/parts/subapp');
subApp.set('env', 'production');

subApp.get('/page', (req, res) => {
res.locals.asdf = 'locals test';
res.render('index.ejs', { message: 'from subapp' });
});

subApp.get('/fallthrough', (req, res, next) => {
next();
});

app.use('/sub', subApp);

app.use((req, res) => {
res.locals.asdf = 'locals test';
res.render('index.ejs', { title: 'Outer', message: 'from outer' });
});

app.use((err, req, res, next) => {
console.log(err.message.split('\n')[0]);
res.status(500).send('whoops!');
});

app.listen(13333, async () => {
console.log('Server is running on port 13333');

// before the router optimization kicks in
console.log(await fetch('http://localhost:13333/sub/page').then(res => res.text()));
console.log(await fetch('http://localhost:13333/sub/fallthrough').then(res => res.text()));

await new Promise(resolve => setTimeout(resolve, 1000));

// after the router optimization kicks in
console.log(await fetch('http://localhost:13333/sub/page').then(res => res.text()));
console.log(await fetch('http://localhost:13333/sub/fallthrough').then(res => res.text()));

process.exit(0);
});
Loading