NextJS Middleware Matcher For Dynamic Routes - javascript

I'm building a website with subdomains. Each subdomain is mapped to a file-based page using middleware. Below is an example of how I'm mapping subdomains to pages:
app.com maps to /home
app.com/pricing maps to /home/pricing
subdomain1.app.com/dashboard maps to /_subdomains/subdomain1/dashboard
subdomain2.app.com/dashboard/home maps to /_subdomains/subdomain2/dashboard/home
app.com, subdomain1.app.com and subdomain1.app.com/dashboard/ and everything else are working fine, but when I try to access subdomain1.app.com/dashboard/home I'm getting 404 Not Found.
Here's my folder structure:
pages/
├── _subdomains/
│ └── [subdomain]/
│ ├── dashboard/
│ │ ├── home.tsx
│ │ └── index.tsx
│ └── index.tsx
├── home/
│ └── ...
└── _app.tsx
import { NextRequest, NextResponse } from 'next/server';
export const config = {
// I have a feeling this isn't matching /_subdomains/subdomain/dashboard/home
matcher: ['/', '/([^/.]*)', '/auth/([^/.]*)', '/_subdomains/:path*'],
};
export default async function middleware(req: NextRequest) {
const url = req.nextUrl;
const hostname = req.headers.get('host') || process.env.ROOT_DOMAIN;
if (!hostname) {
throw Error('Middleware -> No hostname');
}
const currentHost = hostname.replace(`.${process.env.ROOT_DOMAIN}`, '');
if (currentHost === process.env.ROOT_DOMAIN) {
url.pathname = `/home${url.pathname}`;
} else {
console.log(`/_subdomains/${currentHost}${url.pathname}`)
url.pathname = `/_subdomains/${currentHost}${url.pathname}`;
}
return NextResponse.rewrite(url);
}
I'm fairly certain it's the matcher that isn't working but I don't know why.
Matching /_subdomains/:path* should match /_subdomains/a/b/c according to the docs but it isn't working in this case. Or it could be another issue I'm not sure

Fixed by changing the matcher to
matcher: [
/*
* Match all paths except for:
* 1. /api routes
* 2. /_next (Next.js internals)
* 3. /fonts (inside /public)
* 4. /examples (inside /public)
* 5. all root files inside /public (e.g. /favicon.ico)
*/
"/((?!api|_next|fonts|examples|[\\w-]+\\.\\w+).*)",
],
Thanks to this

Related

Find a file by a text that is included in the file name

I have a directory that looks similar to the following
xlsx-modules
├── 0-99
├── 100-199
│   ├── dr111.xls
│   ├── DR115.xls
│   └── DR130.xls
├── 200-299
└── 300-399
└── DR303.xlsx
I try to get the path to the file where the file name includes a code. for example a search with code 111 should return xlxs-modules/100-199/dr111.xls
I have searched for information or an example but without success, could guide me on how to achieve this. Greetings and thanks
I got to solve this problem by implementing
import * as fs from "fs";
import { join } from "path";
export function getFiles() {
const files: string[] = [];
function collectFiles(directory: string) {
const fileList = fs.readdirSync(directory);
for (const fileListElement of fileList) {
const absolutePath = join(directory, fileListElement);
if (fs.statSync(absolutePath).isDirectory()) {
collectFiles(absolutePath);
} else {
files.push(absolutePath);
}
}
}
collectFiles(`${process.cwd()}/xlsx-modules`);
return files;
}
Recursively this function gets a list of the files within the directories, I get a result like this
[
"/home/a123/projects/xlsx-modules/100-199/dr115.xls",
"/home/a123/projects/xlsx-modules/100-199/DR130.xls",
"/home/a123/projects/xlsx-modules/100-199/DR111.xls",
"/home/a123/projects/xlsx-modules/300-399/DR303.xlsx"
]
I use this function to get the files path and then do some string matching
getModuleBy(code: string) {
const files: string[] = getFiles();
const file = files.find((file) => file.includes(code));
if (!file) {
throw new NotFoundException(`Module with code ${code} not found`);
}
return file;
}

GulpJS can no longer finds task in list properly (Gulp 4)

My gulp file pretty much looks like this (simplified)
function copyAssets () {
return src(paths.assets, { base: './' })
.pipe(cache('asset-files'))
.pipe(dest(paths.build))
}
// Some more task functions
const build = parallel(copyAssets, brewCoffee, buildTypescript)
module.exports = { build, watch: series(build, watchFiles) }
But now when I list it it looks like:
[15:29:30] Tasks for .....
[15:29:30] ├─┬ <parallel>
[15:29:30] │ └─┬ <parallel>
[15:29:30] │ ├── copyAssets
[15:29:30] │ ├── brewCoffee
[15:29:30] │ └── buildTypescript
[15:29:30] └─┬ <series>
[15:29:30] └─┬ <series>
[15:29:30] ├─┬ <parallel>
[15:29:30] │ ├── copyAssets
[15:29:30] │ ├── brewCoffee
[15:29:30] │ └── buildTypescript
[15:29:30] └── watchFiles
And running things like gulp build will say that the task does not exist.
If I wrap the series / paralel function in an anonymised function I do see it appear in the list (like so)
const build = () => parallel(copyAssets, brewCoffee, buildTypescript)
module.exports = { build, watch: () => series(build, watchFiles) }
But then when running gulp build I'm getting
Did you forget to signal async completion?
as an error.
I know at some point this did work (a number of months ago). But now for some reason it doesn't anymore. If I run gulp --version the output is:
CLI version: 2.2.0
Local version: 4.0.0
edit: Hmmm. This seems to work
module.exports = { build: () => build(), watch: () => series(build, watchFiles)() }
But I doubt that's how I should actually do this stuff....
edit2: No, still broken, it runs now, and waits until completion. And then says the same error as before: The following tasks did not complete: build
When I have used parallel (very briefly) in the past I had to reference it from gulp.
E.g. Change:
const build = () => parallel(copyAssets, brewCoffee, buildTypescript);
to:
const build = () => gulp.parallel(copyAssets, brewCoffee, buildTypescript);
The same with series here:
module.exports = { build, watch: gulp.series(build, watchFiles) }
Try this:
var srcPaths = {
app: [
'wwwroot/app/**/*.ts'
],
js: [
'node_modules/core-js/client/shim.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/systemjs/dist/system.src.js',
'node_modules/typescript/lib/typescript.js',
'node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js',
'node_modules/moment/moment.js'
],
}
gulp.task('watch', function () {
gulp.watch([srcPaths.app, srcPaths.js], gulp.series('js'));
});
It will work fine. Enjoy!

require and module.exports : TypeError: X is not a function

File structure :
server
├── controllers
│   ├── locationsController.js
│   ├── mainController.js
│   └── utilisateursController.js
├── models
│   ├── Locations.js
│   ├── Utilisateurs.js
| └── ...
├── routes.js
└── server.js
In mainController I have a function isValid to check a string, I put it there because I want to access it from both utilisateursController.js and locationsController.js. I export it as follow :
mainController.js
const lc = require('./locationsController');
const uc = require('./utilisateursController');
// ...
module.exports = {
// Associate all models
associateAll: function () {
lc.associateLocations();
uc.associateUtilisateurs();
},
isValid: function(...fields) {
for (let i = 0; i < fields.length; i++)
if (fields[i] === undefined || fields[i] === null || fields[i] === '')
return false;
return true;
}
};
Problem
I can access the function isValid from utilisateursController.js, but when I try to do the same from locationsController.js, I have this error:
(node:6461) UnhandledPromiseRejectionWarning: TypeError: mc.isValid is not a function
at exports.getAllTasks (.../server/controllers/locationsController.js:30:11)
Code
utilisateursController.js
From this file, I can perfectly access isValid, there is no error.
const mc = require('./mainController');
// ...
exports.login = async function (req, res) {
let response = {
// ...
}
if (req.query == null) {
response.infoMsg = 'Query empty...';
res.send(response);
return;
}
const usernameInput = req.query.username;
const passwordInput = req.query.password;
if (!mc.isValid(usernameInput, passwordInput)) {
response.infoMsg = 'username or password is empty...'
res.send(response);
return;
}
// ...
}
locationsController.js
From this file, I get the error mentioned above, and I really don't know why...
const mc = require('./mainController');
// ...
exports.getAllTasks = async function (req, res) {
let response = {
// ...
}
const usernameInput = req.params.username;
if (!mc.isValid(usernameInput)) {
response.infoMsg = 'No parameters given...';
res.send(response);
return;
}
// ...
}
What I think
I think it is maybe because of the order of the resolutions of the requires...
What the debugger says
utilisateursController.js
locationsController.js
I really don't know what is causing this porblem...
The problem is caused by the fact you have a circular relationship between mainController, utilisateursController, and locationsController. Both utilisateursController and locationsController require mainController, and mainContoller requires both utilisateursController and locationsController. As a result, Node.js's CommonsJS-style module resolution ends up running the top-level code in at least one (probably both) of your modules with a placeholder object for the exports of one of the other modules. (Apparently, in your case, locationsController gets a placeholder for mainController's exports. utilisateursController probably does, too, but doesn't try to use it at the top level.)
If you avoid using mc at the top level, only using it in functions called later, that placeholder will get filled in before you need it and all will be well. The code you've quoted seems to only use mc within a function, but given the error you're getting, apparently that's not true of your real code.
More in the Node.js modules documentation's "Cycles" section.
Side note: This doesn't happen with native JavaScript modules (often called "ESM" for "ECMAScript Modules), because even when there are circular dependencies, they're resolved before the top-level module code gets run.

Webpack font not found

I started learning webpack and I have this small project
I'll be simplifying the content for brevity, hopefully it wont affect your understanding of the problem.
.
└── project
├── dist
│   ├── fonts
│   └── js
├── src
│   ├── app
│ │ ├── app.js
│ │ └── component
│ │ ├── component.css
│ │ ├── component.directive.js
│ │ └── component.html
│   └── fontello
├── index.html
├── package.json
└── webpack.config.js
I'm trying to keep everything inside my component encapsulated so I have:
component.directive.js
require('../../fontello/css/fontello.css');
require('./component.css');
var angular = require('angular');
...
module.exports = angular.module('directives.component', [])
.directive('component', component)
.name;
app.js
var angular = require('angular');
var component = require('./component/component.directive.js');
...
angular.module('app', [component])
and webpack.config.js
var webpack = require('webpack');
module.exports = {
context: __dirname + '/src',
entry: {
app: './app/app.js',
vendor: ['angular']
},
output: {
path: __dirname + '/dist',
filename: 'js/app.bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "js/vendor.bundle.js")
],
module: {
loaders: [{
test: /\.css$/,
loader: 'style-loader!css-loader',
exclude: ['./src/fontello']
}, {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader?name=fonts/[name].[ext]'
}, {
test: /\.html$/,
loader: 'raw'
}]
}
};
and I get for woff2/woff/ttf
404 Not Found. GET http://localhost:8080/fonts/fontello.woff2
what am I doing wrong?

How do you run a pm2 cron job without caring if a process it kicks off has started or not?

To explain my situation. I have a pm2 cron script that I run using:
pm2 start clear-redis-state-cron.js -n clearState --cron '0 0/1 * 1/1 * *'
This runs the js script called clear-redis-state-cron.js just fine.
The role of this script is to stop process p1 and process p2. It then runs a lua redis script that clears some keys from the database. This all works fine but I've put it here for brevity.
var crs = require('./clear-redis-state'),
pm2 = require('pm2');
pm2.connect(function(err) {
pm2.stop('component1');
pm2.stop('component2');
crs.clear();
pm2.restart(__dirname + '/../../node_modules/component1/index.js', { name: 'c1' }, function (err, proc) {
if (err) throw new Error('err');
});
pm2.restart(__dirname + '/../../node_modules/component2/index.js', { name: 'c2' }, function (err, proc) {
if (err) throw new Error('err');
});
});
It runs a clear() js function which is defined here:
var config = require('common/lib/config'),
log = require('common/lib/logger'),
redis = require('common/lib/redis'),
ScriptTo = require('redis-scripto');
exports.clear = function() {
log.init();
if (!config.isSet()) {
// Use local config
var configPath = require('path').join(__dirname, '../../app/config');
config.load(configPath);
}
redis.init(config.get('redis'));
var scriptManager = new ScriptTo(redis.getClient());
scriptManager.loadFromDir(__dirname + '/scripts');
scriptManager.run('clear-state', [], [], function(err, results) {
logError(err);
console.log('results:', results);
});
function logError(err) {
if (err !== null) {
console.log('Error loading lua script merge-keys: ', err);
}
};
}
I have no problems with that. However, it seems to crash on start. Let's say I already have pm2 running two processes component1 and component2 called p1 and p2 respectively. Why would I get the following error when starting the cron when I run it with --no-daemon?
... clear-redis-state-cron.js had too many unstable restarts (15). Stopped. "errored"
My hunch is that either the process is starting up shutting down incorrectly and is in the wrong state as a result so when it tries to close it it's already closed, but because pm2 assumes something went wrong the cron process is stopped.
Any ideas what I might be doing wrong?
Edit: I tried promisifying my shutdown pm2 logic like so:
pm2.connect(function(err) {
Promise.resolve(ops.stop('component1'))
.then(ops.stop('component2'))
.then(ops.clear)
.then(ops.restart(__dirname + '/../../node_modules/component1/index.js', { name: 'component1' }))
.then(ops.restart(__dirname + '/../../node_modules/component2/index.js', { name: 'component2' }))
.catch(logFailureToStop);
});
var logFailureToStop = function (err) {
console.log('Failed to stop ', err);
};
With following result after stopping processes that are running:
$ pm2 list
┌───────────┬────┬──────┬───────┬─────────┬───────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ PID │ status │ restarted │ uptime │ memory │ watching │
├───────────┼────┼──────┼───────┼─────────┼───────────┼────────┼─────────────┼──────────┤
│ component2│ 0 │ fork │ 0 │ stopped │ 17 │ 0 │ 0 B │ disabled │
│ component1│ 1 │ fork │ 18769 │ online │ 31 │ 19s │ 30.539 MB │ disabled │
Managed to resolve this issue in the end.
The issue was caused because I had an on handler event listening into SIGTERM. Apparently these interfere with PM2 so you need to instead use the gracefulStop/gracefulRestart commands.
See: https://github.com/Unitech/PM2/issues/304

Categories