Injecting application level dependency into node module - node.js

I'm trying to create package from higher order components that are currently in application.
The issue is that in some of those components application routes are being used ( through helper that imports all the routes and returns url based on route name ).
I have no idea how to inject those routes to my module from app level.
For example in Symfony ( PHP ) this issue would be fairly simple, due to dependency injection. But with imports inside each file I'm really lost here.
I'm using NextJS and here is code sample ( I would love to inject those routes instead of directly importing them ):
import { routes } from "../../routes";
export default (routeName, params) =>
routes.find(route => route.name === routeName).toPath(params);

You could build your own dependency injection module.
Using NodeJs it's fairly simple to do.
This one for instance.

Related

Running two NestJS applications in the same process

I've been working with Express for a couple of years now and recently got introduced to NestJS. I decided to experiment and write an application on this, as it seemed to me, interesting framework.
I want my application to be able to handle the following routes:
General routes
/policy, /docs
API routes (with versioning)
/api/v1/users, /api/v1/chats
In Express, this is very easy to do, but as I understand it, in NestJS everything is different. As I understand from the documentation, in NestJS you cannot set the path prefix for the entire module. You can only set a global prefix for the entire application.
The documentation also talked about the RouterModule. But I didn’t like it, because it won’t be possible to enable versioning specifically for routes /api and the use of RouterModule itself is very inconvenient. As the application grows, using the RouterModule becomes a pain.
Then I tried to convert the application to a monorepository. It seems to be possible to achieve the desired functionality, but it seems inconvenient for me to run each part of the application separately. Perhaps it would be worth using concurrently, but in my opinion, this is also not the best option.
As a result, I came to the following solution.
The structure of my project at the moment looks like this:
project structure
The api directory will contain all modules related to the api (it will process /api/v1/... routes), and everything else will be in the core (it will process /docs, /policy routes, etc.).
In fact, everything is the same as when creating a monorepository, but I decided to run all this from a single main.ts
main.ts
And I have a question, what are the pitfalls of this solution? Will it affect performance? Are there any better options for solving my problem?
To enable versioning with NestJS :
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI,
});
await app.listen(3000);
Then, it's true that every routes will need version in URL: /v1/...
But you can use VERSION_NEUTRAL to mark default endpoint version :
Some controllers or routes may not care about the version and would
have the same functionality regardless of the version. To accommodate
this, the version can be set to VERSION_NEUTRAL symbol.
An incoming request will be mapped to a VERSION_NEUTRAL controller or
route regardless of the version sent in the request in addition to if
the request does not contain a version at all.
So, for example, here, route /v1/users for Users V1 only :
#Controller({
version: '1',
})
export class UsersControllerV1 {
#Get()
getUsers()...
}
and another route (controller) without any version :
#Controller({
version: VERSION_NEUTRAL,
})
export class PolicyController {
#Get()
getPolicy()...
}
Note that it's possible to provide more than one unique version :
version: ['1', VERSION_NEUTRAL]
More details on official docs.

Prevent webpack from removing crypto in nodejs API

I have a node-js API that's part of an nx workspace and I'm trying to use the core crypto node-js module, however I think it's getting stripped out by webpack.
My code uses the following:
crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
However I get a runtime error:
ReferenceError: crypto is not defined
Am I right in thinking this issue is likely being caused by webpack? And if so, how can I use crypto in my API?
I'm very new to webpack, so I'm pretty clueless here. My nx project uses the #nrwl/node:webpack executor (the default for node-js APIs), and I've followed the steps here on how to customize this projects webpack configuration, so my custom webpack config is being used, I just dont know what to do with it on order to allow my API to use crypto.
Any help on this would be appreciated.
For completeness, here's what my custom webpack config looks like, but it makes no difference to the problem. Note that his was crafted based on some of the suggested answers here:
const { merge } = require('webpack-merge');
/** #type { import('webpack').Configuration } */
const webpackConfig = {
target: 'node',
resolve: {
fallback: {
"crypto": false
}
}
};
module.exports = (config, context) => merge(config, webpackConfig);
Edit: As a workaround, I've imported the randomUUID function from crypto and can use this to do what I need to do. It seems having this import means crypto gets included in the webpack.
import { randomUUID } from 'crypto';
randomUUID().split('-')[0];
In your above code + runtime error, it seems like you haven't imported crypto correctly.
Furthermore you are mixing up some concepts. Webpack is normally used for frontend projects, as Node.js supports requiring modules out of the box and you don't need to compile your code, as you don't need to generate a javascript bundle that's servable by browsers.
Because your project runs in the browser, but your tests run in Node, which has a different global namespace, you get issues. In the browser crypto is defined globally, but in Node you need to import the crypto standard library, the "suggested answers" you are linking to talks about this concept.
To fill in the gap between browser and Node, to ensure the code you write works for test + browser, you use polyfills.
In your usecase you have a Node.js project. Crypto is a standard library for Node.js and you can just require it, why should you configure webpack to create fallbacks for it or use polyfills?

Importing TypeScript types outside of src in React

I have been working on a React + Express project lately which has a project file structure like this:
Repo
|--ExpressApp
|--src/..
|--Common
|--types.ts
|--ReactApp
|--src/..
So the express app lives within the ExpressApp folder, the react app lives within the ReactApp folder, and inside of Common are a set of Typescript types that are shared between the express and react applications.
The react application is a create-react-app project, and I have read issues associated with importing files that reside outside of the react apps src directory. However, in the React application, I seem to be able to import the types that are specified from the Common/types.ts into the React application without any problem.
/** Common/types.ts */
// This imports ok to React app even though its outside of the src directory
export type Person {
id: string,
name: string,
role: string
};
// This does not import into React app, as it is outside of the source directory
export const smapleFunction = () => {
...
}
/** ReactpApp/src/app.ts */
// This is accepted by React
import { Person } from '../../common/types';
// This is not accepted by React
import { sampleFunction } from '../../common/types';
If I was to export a function from the Common/types.ts file and use it within the React application, then react throws the expected error that files must reside within the src directory - however, no issue is found when importing types, interfaces etc.
Could somebody please explain why this seems to be work for typescript types residing outside of src, but not for functions or other modules? I'm assuming it has something to do with how Typescript is handled within a CRA project, but I don't quite understand the process?
Types and Interfaces are not compiled, so they are essentially removed as the first part of the build process, and the build can keep on going. But the rest of the build process depends on all the code existing in the src folder, and the common function code (which is compiled) does not exist in that directory.

Set Base URL for Preact CLI

Using Preact CLI is it possible to set the path where the app will be hosted outside of the root directory?
For instance hosting the app at http://mywebsite.com/relativepath/index.html
You have several problems to solve:
1. Get Webpack to output the correct paths in your html
This is done via creating a preact.config.js in your root folder, and put the following in there
export default (config) => {
config.output.publicPath = '/relativepath/';
};
2. Set your navigation and assets links in your app
The best way to solve it in my opinion is to use a global variable which you can be used in your app. So again, edit the preact.config.js to the following:
export default (config, env, helpers) => {
config.output.publicPath = '/relativepath/';
// use the public path in your app as 'process.env.PUBLIC_PATH'
config.plugins.push(
new helpers.webpack.DefinePlugin({
'process.env.PUBLIC_PATH': JSON.stringify(config.output.publicPath || '/')
})
);
};
3. Routing
When using your preact app, it should be no problem to navigate. However, if you try to load a fresh URL e.g. www.myserver.com/relativepath/mything/9, the server doesn't know that it should load your single page app living at www.myserver.com/relativepath/index.html
You have two options:
a) Server-side routing
Make sure your all the requests to relativepath (including e.g. relativepath/mything/9) will be rewritten to your app's relativepath/index.html (in case of using Apache).
Then your Javascript can process the routes, e.g. preact-router
b) Client-side routing (recommended)
The easier option for enabling reloading of URLs is to use hash urls, thereby avoid going through the server when loading a URL.
Your URLs will look something like www.myserver.com/relativepath/#/mything/9
The server ignores the part after # and only loads (hopefully) /relativepath/index.html
You can use e.g. the preact-router with Hash History to avoid server-side routing, read about it here https://github.com/developit/preact-router#custom-history
I'm proxying from http-proxy-middleware to the preact-cli dev server and these settings worked for me in preact.config.js
export default (config, env, helpers) => {
config.output.publicPath = '/relativepath';
config.devServer.devMiddleware.publicPath = "/relativepath";
};

Webpack-dev-server and isomorphic react-node application

I've managed to properly use webpack dev server alongside with a node server (express), using the plugin section inside webpack's config.
It all works fine but now I'm trying to go isomorphic and use client-side components inside the express application.
So far the only problem I'm encountering is that without webpack 'parsing' my server-side code I get to a situation where I require components but the paths are not solved
I.E.
Inside a component
'use strict';
import React from 'react';
import { RouteHandler, Link } from 'react-router';
import Header from 'components/header/main'; // <-- This line causes the error because webpack is not working when parsing this JSX server-side
export default React.createClass({
displayName: 'App',
render() {
return ( // ... More code
Shall I configure webpack in another way or do I have to change all the imports to be valid server-side?
the codebase is here in case you want to see the actual state https://github.com/vshjxyz/es6-react-flux-node-quickstart
In order to be able to require components in a way such as require('components/Header.js'); and avoid using long relative paths such as require('../../../../../../Header.js'); you can add this code to your node app before any require() calls:
process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();
However, since this relies on a private Node.js core method, this is
also a hack that might stop working on the previous or next version of
node.
Other possible solutions to this problem can be found at https://gist.github.com/branneman/8048520
I see 2 options:
Compile client code with webpack as well. If client's entry
point is in the same dir as server's - it should work with your
present code. This looks natural to me.
Use relative paths i.e.
import Header from './components/header/main'

Resources