Multiple NPM repos in one GitHub repo with scoping? - node.js

Let's say I have a client, awesome-service that composes of different types of services, http-service, log-service, etc...
I want to have the option of either including each individual service (and a specific version), or just require all of the awesome-services, so in effect I want something like:
const awesomeService = require('#awesome-service');
// Now awesomeService has
// awesomeService.httpService;
// awesomeService.logService;
// etc
// or individually
const httpService = require('#awesome-service/http-service');
Is this possible? What would the package.json and the GitHub organization look like? Maybe this is package.json?
"dependencies": {
"awesome-service": "#awesome-service"
// OR if individually importing them
"http-service": "#awesome-service/http-service#1.0.0"
}
How can this be accomplished, or rather can this be accomplished?

Is this possible?
Yes, it's possible.
What would the package.json and the GitHub organization look like?
The package should have the following structure:
- awesome-service
- index.js // main module
- package.json // package.json of the main package
- http-service
- index.js // implementation of `http` service
- package.json // package.json of `http` package
- log-service
- index.js // implementation of `log` service
- package.json // package.json of `log` package
As you see there are three package.json files. The root is used for main package, others for each service.
In each package.json, set main field to index.js and set a correct name for each package:
{
"name": "awesome-service",
"main": "index.js",
...
}
{
"name": "awesome-service#http-service",
"main": "index.js",
...
}
{
"name": "awesome-service#log-service",
"main": "index.js",
...
}
In index.js of the root package export the object with the fields - required services (I don't specify index.js in requires, because this module will be loaded by default):
module.exports = {
httpService: require('./http-service'),
logService: require('./log-service')
};
To use these three package separately, you should add all of them in npm, or use github with a proper url:
"dependencies": {
"awesome-service": "awesome-service"
"http-service": "awesome-service#http-service#1.0.0",
"log-service": "git+https://github.com/yourAccount/awesome-service/log-service.git"
}

Related

How I can use a commonjs module in my quasar project

I an SSR Quasar project using Vite. Whenever I try to add the #tiptap/extension-code-block-lowlight extension to my project, build it and then node dist/ssr/index.js it throws the following error:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/whatever/devotto/devotto.com/node_modules/lowlight/lib/common.js
require() of ES modules is not supported.
require() of /home/whatever/devotto/devotto.com/node_modules/lowlight/lib/common.js from /home/whatever/devotto/devotto.com/dist/ssr/server/server-entry.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename common.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/whatever/devotto/devotto.com/node_modules/lowlight/package.json.
Upon investigation, I have concluded that the issue is the lowlight library being imported by #tiptap/extension-code-block-lowlight.
If I manually go to my node_modules/#tiptap/extension-code-block-lowlight/package.json AND node_modules/lowlight/package.json and remove the line "type": "module", I can run the project with no problem (e.g. yarn build && node dist/ssr/index.js.
This solution works on my current machine but I shouldn't have to touch the node_modules folder.
I would assume that I have to transpile lowlight library which prompts me to try to alter Vite configuration but no luck there as well
module.exports = function() {
return {
build: {
extendViteConf (viteConf, { isClient, isServer }) {
if (isServer) {
viteConf.optimizeDeps = viteConf.optimizeDeps || {};
viteConf.optimizeDeps.include = ['./node_modules/highlight.js'];
viteConf.build.commonjsOptions = viteConf.build.commonjsOptions || {};
viteConf.build.commonjsOptions.include = [/highlight.js/, /node_modules/];
// viteConf.optimizeDeps.entries = [
// 'node_modules/#tiptap/extension-code-block-lowlight/dist/tiptap-extension-code-block-lowlight.cjs',
// 'node_modules/highlight.js'
// ];
}
},
}
}
}
Is there a solution to this issue without having to manually change node_module folder? Thank you very much in advance.
I didn't exactly solve the question. I only applied an automated way to handle this whenever I run the command to build the server using pre scripts.
On my package.json:
{
"scripts": {
"start:test:webserver": "ENV_FILE=test quasar build --mode ssr --port 3000 && node dist/ssr/index.js",
"prestart:test:webserver": "sed -i '/\"type\": \"module\",/d' node_modules/lowlight/package.json && sed -i '/\"type\": \"module\",/d' node_modules/#tiptap/extension-code-block-lowlight/package.json",
}
}

Access config values in package.json

I have recently introduced https://www.npmjs.com/package/config to handle my config:
...
config/
dev.json
uat.json
production.json
package.json
In dev.json I have something like:
{
"someVar": "something"
}
I used to be able to access config values in package.json like:
"scripts": {
"some_command": "do_something $npm_package_config_someVar"
}
But now this doesn't work - those variables are empty.
How can I access values from config/dev.json in packages.json?
Edit: using $npm_config_someVar is also empty
var pkg = require('./package.json');
console.log(pkg.name);

Importing typescript from external node modules

I want to split my application into different node modules and have a main module which builds all other modules as well and I want to use typescript with es6 modules.
Here is my planned project structure:
main
node_modules
dep-a
dep-b
framework
interfaces
IComponent.ts
dep-a
components
test.ts
node_modules
framework
index.ts
dep-b
node_modules
framework
I want to be able to define interfaces in framework which can be consumed in dep-a, dep-b and main.
How do I set up this correctly? Can I compile everything from my main-module? Do I need to create different bundles for framework, dep-a, ... and another typing file? What is the best approach for this?
I already set up some test files and folders and used npm link to link the dependencies and webpack to bundle the files and I am always running into issues with files not being found:
error TS2307: Cannot find module 'framework/interfaces/IComponent'
and
Module not found: Error: Cannot resolve 'file' or 'directory' ./components/test
TL;DR generate declarations for the modules using declaration: true in tsconfig.json and specify the file for your generated typings in the typings entry of the package.json file
framework
Use a tsconfig file similar to this:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"noImplicitAny": true,
"removeComments": true,
"outDir": "dist",
...
},
"files": [
...
]
}
The important bit is declaration: true which will generate internal declarations in the dist directory
Assuming there is an index.ts file which (re)exports all the interesting parts of framework, create a package.json file with a main and typings entry pointing to, respectively, the generated js and the generated declaration, i.e.
{
"name": "framework",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
...
}
Commit this module to a git repo, say bitbucket at : "https://myUser#bitbucket.org/myUser/framework.git"
dep-a
in package.json create a dependency to framework
{
"dependencies": {
"framework": "https://myUser#bitbucket.org/myUser/framework.git"
},
}
That is it.
import * from 'framework'
will pull the dependency with the typings, automatically
Obviously, it is possible to do with dep-a what was done with framework i.e. generate the declarations, update package.json and use dep-a as a module with embedded typings in main
note: a file URL will do in package.json/dependencies if you do not want go to via an external git repo
What arrived in TypeScript 1.6 is typings property in package.json module. You can check the relevant issue on GitHub.
So assuming you want to create separate modules ( dep-a, framework ). You can do the following :
main.ts // (1)
package.json // (2)
node_modules/
dep_a/
index.js // (3)
index.d.ts // (4)
package.json // (5)
node_modules/
framework/
index.js // (6)
index.d.ts // (7)
package.json // (8)
So let's see what you have in your files :
//(1) main.ts
import * as depA from "depA";
console.log(depA({ a : true, b : 2 }) === true) // true;
//(2) package.json
{
name: "main",
dependencies: {
"dep_a" : "0.0.1"
}
...
}
For depA
//(3) dep_a/index.js
module.exports = function a(options) { return true; };
//(4) dep_a/index.d.ts;
import * as framework from "framework";
export interface IDepA extends framework.IFramework {
a : boolean
}
export default function a(options: IDepA) : boolean;
//(5) dep_a/package.json
{
name: "dep_a",
dependencies: {
"framework" : "0.0.1"
},
...
typings : "index.d.ts" // < Magic happens here
}
For framework
//(6) dep_a/node_modules/framework/index.js
module.exports = true // we need index.js here, but we will only use definition file
//(7) dep_a/node_modules/framework/index.d.ts;
export interface IFramework {
b : number;
}
//(8) dep_a/node_modules/framework/package.json
{
name: "framework"
...
typings : "index.d.ts"
}
What I don't include in this answer ( for clarity ) is another compilation phase, so you could actually write the modules ( dep_a, framework ) with typescript and then compile them to index.js before you use them.
For a detailed explanation and some background also see: https://medium.com/#mweststrate/how-to-create-strongly-typed-npm-modules-1e1bda23a7f4

Require dependency of dependency

I have the modules as shown above. I need to include not only quickblox, but the quickblox.chat plugin.
I'm using this code:
// Quickblox
var QB = require('quickblox');
var QBChat = require('quickblox/plugins/chat');
quickblox loads fine but quickblox/plugins/chat throws:
Error: Cannot find module 'quickblox/plugins/chat'
Here is the package.json included in the quickblox/plugins/chat directory:
{
"name": "quickblox.chat",
"description": "Quickblox Javascript SDK / XMPP Chat plugin",
"version": "0.8.6",
"author": "Andrey Povelichenko <andrey.povelichenko#quickblox.com>",
"homepage": "http://quickblox.com/developers/Web_XMPP_Chat_Sample"
}
If you call require with a folder path, it tries to load index.js, which doesn't exist.
var QBChat = require('quickblox/plugins/chat/quickblox.chat');

How to browserify a standalone module for use in WebWorkers

I am using browserify to create standalone modules that I can use in node.js and client side in browser. I don't use browserify on the entire app, just a few single node modules.
I do browserify-shim to shim e.g. lodash under the global var _.
This works very well except when using the modules inside webworkers.
The problem is:
When I shim lodash as _ the browserified code sets var _ = window._,
but windows is not defined inside the web workers.
My setup
I use grunt to browserify, and have browserify-shim configured in my package.json
map.js: (commonJS module, used directly in node.js)
var _ = require('lodash-node');
module.exports = _.map;
GruntFile.js:
// Browserify
grunt.loadNpmTasks('grunt-browserify');
grunt.initConfig({
browserify: {
'map': {
options: {
bundleOptions: {
standalone: 'MapModule'
}
},
src: ['./map.js'],
dest: './output/map-module.js'
}
}
});
grunt.registerTask('default', [
'browserify'
]);
package.json:(partial)
{
"name": "APP NAME",
"version": "0.0.0",
"description": "",
"main": "app.js",
"browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"lodash-node": "global:_"
},
}
The output
the generated output from browserify looks like this:
https://gist.github.com/mikaelhm/859735472c9b0038770e
Note line 2: var _ = (window._);
Thats a problem in a Web Worker.
Am I doing it all wrong, or is it only supposed to work in normal browsing mode?
I know this is an old post but I'm sharing the solution I found as this took me a few hours to find a solution.
I managed to get web workers running as modules using
https://github.com/substack/webworkify it's avaliable as via npm install webworkify.
A task I had to perform inside my web worker was to parse an xml string to javascript this I did with xmldoc, as xmldoc does not require a DOM and there is no DOM in web workers.
I include xmldoc in my web worker with require, which would be the same for lodash.

Resources