Using a browserified JS library with Angular 2 - javascript

I want to use libquassel (https://github.com/magne4000/node-libquassel) in my Angular 2 project. The library is browserified, so in theory it should work, but I'm not really sure how to import it in my project.
I tried adding to my typings.d.ts
declare module 'libquassel';
and then importing the library with
import * as Quassel from 'libquassel';
but I get
EXCEPTION: net.Socket is not a function
when I try to run my code, which I believe is another library that browserify embedded in the client/libquassel.js file.
How can I use this library?
Edit: I'll answer all questions here:
My setup is a plain angular-cli project. No fancy stuff, just ng new proj1 and then npm install libquassel --save.
My index.html doesn't have anything else that ng new hasn't placed in there.
I tried importing the library with import * as Quassel from 'libquassel' and var Quassel = require('quassel') (and permutations of those), without any luck (errors varying from unknown function 'require' to can't find module lib|quassel).
Steps to repro my project:
ng new test
cd test
npm install libquassel --save
ng g s quassel
Then add QuasselService to the providers array in app.module.ts.
This would be a good demo of my problem, which is how to import libquassel in my QuasselService.

Update (fix it, this time for real)
There is a very good reason why it doesn't work in your code: because I lied to you. So here is my real cheat in case you didn't "diffed" it yourself yet.
I still need to require libquassel 2 times but the first time is done not by the call to require which is useless but by adding it to angular-cli.json to the scripts section:
"scripts": [
"../node_modules/libquassel/client/libquassel.js"
],
This is important because "client/libquassel.js" declares its own require but do not explicitly exports it so if you do
require('libquassel/client/libquassel.js');
libquassel's custom require is left stuck inside anonymous namespace and you can't access it. Adding it to the scripts section on the other hand, lets libquassel.js to pollute the global namespace (i.e. window) with its require and thus make it work.
So the actual steps to make it work are:
Add client/libquassel.js to the scripts section of angular-cli.json
Use additional require to actually load Quassel module
let Quassel = window['require']('quassel'); // note that usingg require('quassel') leads to compilation error
let quasselObj = new Quassel(...);
Here is my attempt. It looks like you need to require "quassel" 2 times: first time to load the JS from "../node_modules/libquassel/client/libquassel.js" and second time to let the overridden require from that JS actually resolve "quassel". Here is a trick that seems to work for me in 'main.ts':
require('../node_modules/libquassel/client/libquassel.js');
let Quassel = window['require']('quassel'); // note that using require('quassel') leads to compilation error
let quasselObj = new Quassel(...);
I needed one more trick to not fail with a compilation error: particularly I had to use window['require'] instead of just require for the second call as it is a call for the inner require as defined inside client/libquassel.js and Node/Angular-cli alone can't handle it.
Note that after that setup my application still failed with a runtime error in some AJAX because browsified libquassel.js seem to require a proxy set up on the server-side at URL like /api/vm/net/connect and this is probably what server-side of the net-browsify should do but I didn't try to set it up.
Answer to comments
It looks like you use old version of Angular-CLI and if you upgrade everything should work fine.
Here is what ng --version tells me on my original machine
angular-cli: 1.0.0-beta.28.3
node: 6.10.0
os: win32 x64
#angular/common: 2.4.10
#angular/compiler: 2.4.10
#angular/core: 2.4.10
#angular/forms: 2.4.10
#angular/http: 2.4.10
#angular/platform-browser: 2.4.10
#angular/platform-browser-dynamic: 2.4.10
#angular/router: 3.4.10
#angular/compiler-cli: 2.4.10
When I tried to copy my original project to a different machine I also got a compilation error about require but when I updated Angular-CLI to
#angular/cli: 1.0.0
node: 6.10.0
os: darwin x64
#angular/common: 2.4.10
#angular/compiler: 2.4.10
#angular/core: 2.4.10
#angular/forms: 2.4.10
#angular/http: 2.4.10
#angular/platform-browser: 2.4.10
#angular/platform-browser-dynamic: 2.4.10
#angular/router: 3.4.10
#angular/cli: 1.0.0
#angular/compiler-cli: 2.4.10
it compiled and worked the same. What I did is just followed the instruction
The package "angular-cli" has been deprecated and renamed to "#angular/cli".
Please take the following steps to avoid issues:
"npm uninstall --save-dev angular-cli"
"npm install --save-dev #angular/cli#latest"
and then updated angular-cli.json following the instructions by ng serve

Works like a charm :
declare var require;
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
Looking at the libquassel's folder in node_module, realised that there is no index.js in the root directory.
When there is not index.js , you can't do this :
require( 'libquassel' );
Simply because node doesn't know what to pull in for you, so you'd need to specify the exact path, which is not that bad in this case.
Also , note that it's better to move declare var require; to your typings file located under the src folder, because you might need to declare it again , so it's better be there.
EDIT :
Here is what I found after trying to instantiate the Quassel like bellow :
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
var quassel = new Quassel( "quassel.domain.tld",
4242,
{ backloglimit : 10 },
function ( next ) {
next( "user", "password" );
} );
console.log( 'quassel', quassel );
And here is my console log :
But having said that, I realised that there is a problem inside the libquassel.js , as bellow :
in line 10, they're doing this :
var net = require('net');
And looking their package.json, there is no such a thing as net and there is net-browserify-alt;
So if they change that import to :
var net = require('net-browserify-alt'),
Everything will work.
Having said that, obviously you don't want to edit your node_module, but I'm really surprised of how this really works even outside of angular and webpack , because clearly they've mentioned a wrong node_module which if you google , there is only one package named net which I had a look and it's empty and dummy !!!!
** ********** UPDATE : ********** **
What exactly needs to be done :
1- run ng eject
that will generate a webpack.conf.js inside your root directory.
2- inside that find resolve property and add :
"alias":{
'net':'net-browserify-alt'
},
so your resolve will probably look like :
"resolve": {
"extensions": [
".ts",
".js"
],
"alias":{
'net':'net-browserify-alt'
},
"modules": [
"./node_modules"
]
},
3- import and use it :
declare var require;
const Quassel = require( 'libquassel/lib/libquassel.js' );
console.log( 'Quassel', Quassel );
var quassel = new Quassel( "quassel.domain.tld",
4242,
{ backloglimit : 10 },
function ( next ) {
next( "user", "password" );
} );
console.log( 'quassel', quassel );
NOTE :
Having a look at webpack configuration, seems like webpack likes to override couple of modules :
"node": {
"fs": "empty",
"global": true,
"crypto": "empty",
"tls": "empty",
"net": "empty",
"process": true,
"module": false,
"clearImmediate": false,
"setImmediate": false
}
I don't exactly know why, but this list is in the webpack config and seems to be making net to be undefiend ( empty ) and that's why we had to create an alias.

Angular-cli uses webpack
you will need to add the JS file to apps[0].scripts in your angular-cli.json file, which WebPack then bundles as if it were loaded with a tag.
apps:[
{
...
"scripts": [
"../node_modules/libquassel/client/libquassel.js"
],
If you do that, you can get at it by adding declare var Quassel :any; in your src/typings.d.ts or component.
let quassel = new Quassel("localhost", 4242, {}, function(next) {
next("user", "password");
});
quassel.connect();

The key issue is the browserified libquassel library contains within it a global require function. That conflicts with standard require function.
There are many ways of handling this but one solution would be to copy /libquassel/client/libquassel.js (and the minified version) to your /src/app/ directory.
Then run a search and replace in these files to change ALL occurrences of require to _quasselRequire_
You would do this for both libquassel.js and libquassel.min.js.
To utilise this you would do something like this in quassel.service.ts:
import { Injectable } from '#angular/core';
import * as dummyQuassel1 from './libquassel.js'
var dummyQuassel2 = dummyQuassel1; // something just to force the import
declare var _quasselRequire_ :any;
#Injectable()
export class QuasselService {
constructor() {
// set up in the constructor as a demo
let Quassel = _quasselRequire_( 'quassel' );
console.log('Quassel', Quassel);
var quassel = new Quassel(
"quassel.domain.tld",
4242,
{ backloglimit : 10 },
function ( next ) {
next( "user", "password" );
}
);
console.log('quassel', quassel);
quassel.on('network.init', function(networkId) {
console.log("before net");
var network = quassel.getNetworks().get(networkId);
console.log("after net");
// ...
});
console.log("before connect");
quassel.connect();
console.log("after connect");
}
getQuassel() {
return 'My Quassel service';
}
}
This by itself results in the error:
POST http://localhost:4200/api/vm/net/connect 404 (Not Found)
and
Error: Uncaught, unspecified 'error' event.
at new Error (native)
at Quassel.n.emit (http://localhost:4200/main.bundle.js:570:4210) [angular]
at Socket. (http://localhost:4200/main.bundle.js:810:19931) [angular]
at Socket.EventEmitter.emit (http://localhost:4200/main.bundle.js:573:1079) [angular] ...
But as I understand it this is fairly normal given I haven't Express etc. set up.
Note: the name _quasselRequire_ can be anything that's appropriate to you.

Related

Adding opentelemetry tracing to Node.js app breaks `require("fs").realpathSync.native`

Using the following tracing enabling script from OpenTelemetry docs:
const opentelemetry = require("#opentelemetry/sdk-node");
const { getNodeAutoInstrumentations } = require("#opentelemetry/auto-instrumentations-node");
const { diag, DiagConsoleLogger, DiagLogLevel } = require('#opentelemetry/api');
// For troubleshooting, set the log level to DiagLogLevel.DEBUG
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
const sdk = new opentelemetry.NodeSDK({
traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start()
running my Next.js server as I thought is required, I get an error:
$ node --require './tracing/opentelemetry.js' ./node_modules/next/dist/bin/next start -p 3000
No modules instrumentation has been defined, nothing will be patched
#opentelemetry/instrumentation-grpc Module #grpc/grpc-js has been loaded before #opentelemetry/instrumentation-grpc so it might not work, please initialize it before requiring #grpc/grpc-js
Exporter "otlp" requested through environment variable is unavailable.
/mnt/vol/.local/share/pnpm/global/5/.pnpm/next#12.1.5_zpnidt7m3osuk7shl3s4oenomq/node_modules/next/dist/lib/get-project-dir.js:40
const realDir = _fs.default.realpathSync.native(resolvedDir);
^
TypeError: _fs.default.realpathSync.native is not a function
at Object.getProjectDir (/mnt/vol/.local/share/pnpm/global/5/.pnpm/next#12.1.5_zpnidt7m3osuk7shl3s4oenomq/node_modules/next/dist/lib/get-project-dir.js:40:50)
at nextStart (/mnt/vol/.local/share/pnpm/global/5/.pnpm/next#12.1.5_zpnidt7m3osuk7shl3s4oenomq/node_modules/next/dist/cli/next-start.js:80:37)
at /mnt/vol/.local/share/pnpm/global/5/.pnpm/next#12.1.5_zpnidt7m3osuk7shl3s4oenomq/node_modules/next/dist/bin/next:141:34
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Node.js v17.8.0
Now this can be simplified to a minimal reproduction as follows. This has the fs.realpathSync.native function:
$ node -e 'console.log(require("fs").realpathSync)'
[Function: realpathSync] { native: [Function (anonymous)] }
This doesn't have fs.realpathSync.native:
$ node --require ./tracing/opentelemetry.js -e 'console.log(require("fs").realpathSync)'
No modules instrumentation has been defined, nothing will be patched
#opentelemetry/instrumentation-grpc Module #grpc/grpc-js has been loaded before #opentelemetry/instrumentation-grpc so it might not work, please initialize it before requiring #grpc/grpc-js
[Function (anonymous)]
Exporter "otlp" requested through environment variable is unavailable.
My Node's --require is working correctly (noop.js is an empty file):
$ node --require ./tracing/noop.js -e 'console.log(require("fs").realpathSync)'
[Function: realpathSync] { native: [Function (anonymous)] }
Why would the OpenTelemetry setup script break the fs module?
$ node --version
v17.8.0
//package.json dependencies
"#opentelemetry/api": "^1.3.0",
"#opentelemetry/auto-instrumentations-node": "^0.35.0",
"#opentelemetry/sdk-node": "^0.34.0",
$ uname -a
Linux code-server 5.15.0-1025-oracle #31~20.04.2-Ubuntu SMP Tue Nov 29 13:01:56 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux
Does my ARM machine have something to do with it?
I can reproduce the same on x86_64 on https://replit.com/#JakubKoralewski/opentelemetry-repro with the same behavior.
The reason this error occurs is due to a bug in #opentelemetry/instrumentation-fs introduced as a new dependency to #opentelemetry/auto-instrumentations-node in PR #981 which got released with version 0.34.0. The issue was reported but at the time of writing is still open. However, as also already linked above a PR to address the issue is being reviewed.
Fow now, I see three ways to address the problem:
As suggested in a comment above downgrade #opentelemetry/auto-instrumentations-node to next lower version 0.33.1.
Disable the file system instrumentation when configuring the node instrumentation. For that simply replace getNodeAutoInstrumentations() with getNodeAutoInstrumentations({ '#opentelemetry/instrumentation-fs': { enabled: false } }) in your code. Given that your project is in Next.js and you likely have little file system activity aside from maybe public files this is likely the best option for now.
Remove #opentelemetry/auto-instrumentations-node altogether and simply instrument the libraries you actually use. Using the auto instrumentation for Node.js pulls in a lot of transitive dependencies. Say you have a Next.js app, connect to a Postgres database and use winston for logging your instrumentation setup could look something like this:
const sdk = new opentelemetry.NodeSDK({
traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
instrumentations: [
// new FsInstrumentation(), TODO: re-enable once bug is fixed
new HttpInstrumentation(),
new PgInstrumentation(),
new WinstonInstrumentation(),
]
});

Renaming file by using Node Package Version [duplicate]

Is there a way to get the version set in package.json in a nodejs app? I would want something like this
var port = process.env.PORT || 3000
app.listen port
console.log "Express server listening on port %d in %s mode %s", app.address().port, app.settings.env, app.VERSION
I found that the following code fragment worked best for me. Since it uses require to load the package.json, it works regardless of the current working directory.
var pjson = require('./package.json');
console.log(pjson.version);
A warning, courtesy of #Pathogen:
Doing this with Browserify has security implications.
Be careful not to expose your package.json to the client, as it means that all your dependency version numbers, build and test commands and more are sent to the client.
If you're building server and client in the same project, you expose your server-side version numbers too.
Such specific data can be used by an attacker to better fit the attack on your server.
If your application is launched with npm start, you can simply use:
process.env.npm_package_version
See package.json vars for more details.
Using ES6 modules you can do the following:
import {version} from './package.json';
Or in plain old shell:
$ node -e "console.log(require('./package.json').version);"
This can be shortened to
$ node -p "require('./package.json').version"
There are two ways of retrieving the version:
Requiring package.json and getting the version:
const { version } = require('./package.json');
Using the environment variables:
const version = process.env.npm_package_version;
Please don't use JSON.parse, fs.readFile, fs.readFileSync and don't use another npm modules it's not necessary for this question.
For those who look for a safe client-side solution that also works on server-side, there is genversion. It is a command-line tool that reads the version from the nearest package.json and generates an importable CommonJS module file that exports the version. Disclaimer: I'm a maintainer.
$ genversion lib/version.js
I acknowledge the client-side safety was not OP's primary intention, but as discussed in answers by Mark Wallace and aug, it is highly relevant and also the reason I found this Q&A.
Here is how to read the version out of package.json:
fs = require('fs')
json = JSON.parse(fs.readFileSync('package.json', 'utf8'))
version = json.version
EDIT: Wow, this answer was originally from 2012! There are several better answers now. Probably the cleanest is:
const { version } = require('./package.json');
There is another way of fetching certain information from your package.json file namely using pkginfo module.
Usage of this module is very simple. You can get all package variables using:
require('pkginfo')(module);
Or only certain details (version in this case)
require('pkginfo')(module, 'version');
And your package variables will be set to module.exports (so version number will be accessible via module.exports.version).
You could use the following code snippet:
require('pkginfo')(module, 'version');
console.log "Express server listening on port %d in %s mode %s", app.address().port, app.settings.env, module.exports.version
This module has very nice feature - it can be used in any file in your project (e.g. in subfolders) and it will automatically fetch information from your package.json. So you do not have to worry where you package.json is.
I hope that will help.
NPM one liner:
From npm v7.20.0:
npm pkg get version
Prior to npm v7.20.0:
npm -s run env echo '$npm_package_version'
Note the output is slightly different between these two methods: the former outputs the version number surrounded by quotes (i.e. "1.0.0"), the latter without (i.e. 1.0.0).
One solution to remove the quotes in Unix is using xargs
npm pkg get version | xargs echo
Option 1
Best practice is to version from package.json using npm environment variables.
process.env.npm_package_version
more information on: https://docs.npmjs.com/using-npm/config.html
This will work only when you start your service using NPM command.
Quick Info: you can read any values in pacakge.json using process.env.npm_package_[keyname]
Option 2
Setting version in environment variable using https://www.npmjs.com/package/dotenv as .env file and reading it as process.env.version
Just adding an answer because I came to this question to see the best way to include the version from package.json in my web application.
I know this question is targetted for Node.js however, if you are using Webpack to bundle your app just a reminder the recommended way is to use the DefinePlugin to declare a global version in the config and reference that. So you could do in your webpack.config.json
const pkg = require('../../package.json');
...
plugins : [
new webpack.DefinePlugin({
AppVersion: JSON.stringify(pkg.version),
...
And then AppVersion is now a global that is available for you to use. Also make sure in your .eslintrc you ignore this via the globals prop
If you are looking for module (package.json: "type": "module") (ES6 import) support, e.g. coming from refactoring commonJS, you should (at the time of writing) do either:
import { readFile } from 'fs/promises';
const pkg = JSON.parse(await readFile(new URL('./package.json', import.meta.url)));
console.log(pkg.version)
or, run the node process with node --experimental-json-modules index.js to do:
import pkg from './package.json'
console.log(pkg.version)
You will however get a warning, until json modules will become generally available.
If you get Syntax or (top level) async errors, you are likely in a an older node version. Update to at least node#14.
You can use ES6 to import package.json to retrieve version number and output the version on console.
import {name as app_name, version as app_version} from './path/to/package.json';
console.log(`App ---- ${app_name}\nVersion ---- ${app_version}`);
A safe option is to add an npm script that generates a separate version file:
"scripts": {
"build": "yarn version:output && blitz build",
"version:output": "echo 'export const Version = { version: \"'$npm_package_version.$(date +%s)'\" }' > version.js"
}
This outputs version.js with the contents:
export const Version = { version: "1.0.1.1622225484" }
To determine the package version in node code, you can use the following:
const version = require('./package.json').version; for < ES6 versions
import {version} from './package.json'; for ES6 version
const version = process.env.npm_package_version;
if application has been started using npm start, all npm_* environment variables become available.
You can use following npm packages as well - root-require, pkginfo, project-version.
we can read the version or other keys from package.json in two ways
1- using require and import the key required e.g:
const version = require('./package.json')
2 - using package_vars as mentioned in doc
process.env.npm_package_version
You can use the project-version package.
$ npm install --save project-version
Then
const version = require('project-version');
console.log(version);
//=> '1.0.0'
It uses process.env.npm_package_version but fallback on the version written in the package.json in case the env var is missing for some reason.
Why don't use the require resolve...
const packageJson = path.dirname(require.resolve('package-name')) + '/package.json';
const { version } = require(packageJson);
console.log('version', version)
With this approach work for all sub paths :)
In case you want to get version of the target package.
import { version } from 'TARGET_PACKAGE/package.json';
Example:
import { version } from 'react/package.json';
I know this isn't the intent of the OP, but I just had to do this, so hope it helps the next person.
If you're using docker-compose for your CI/CD process, you can get it this way!
version:
image: node:7-alpine
volumes:
- .:/usr/src/service/
working_dir: /usr/src/service/
command: ash -c "node -p \"require('./package.json').version.replace('\n', '')\""
for the image, you can use any node image. I use alpine because it is the smallest.
The leanest way I found:
const { version } = JSON.parse(fs.readFileSync('./package.json'))
I've actually been through most of the solutions here and they either did not work on both Windows and Linux/OSX, or didn't work at all, or relied on Unix shell tools like grep/awk/sed.
The accepted answer works technically, but it sucks your whole package.json into your build and that's a Bad Thing that only the desperate should use temporarily to get unblocked, and in general should be avoided, at least for production code. The alternative is to use that method only to write the version to a single constant that can be used instead of the whole file.
So for anyone else looking for a cross-platform solution (not reliant on Unix shell commands) and local (without external dependencies):
Since it can be assumed that Node.js is installed, and it's already cross-platform for this, I just created a make_version.js file with:
const PACKAGE_VERSION = require("./package.json").version;
console.log(`export const PACKAGE_VERSION = "${PACKAGE_VERSION}";`);
console.error("package.json version:", PACKAGE_VERSION);
and added a version command to package.json:
scripts: {
"version": "node make_version.js > src/version.js",
and then added:
"prebuild": "npm run version",
"prestart": "npm run version",
and it creates a new src/versions.js on every start or build. Of course this can be easily tuned in the version script to be a different location, or in the make_version.js file to output different syntax and constant name, etc.
I do this with findup-sync:
var findup = require('findup-sync');
var packagejson = require(findup('package.json'));
console.log(packagejson.version); // => '0.0.1'
I am using gitlab ci and want to automatically use the different versions to tag my docker images and push them. Now their default docker image does not include node so my version to do this in shell only is this
scripts/getCurrentVersion.sh
BASEDIR=$(dirname $0)
cat $BASEDIR/../package.json | grep '"version"' | head -n 1 | awk '{print $2}' | sed 's/"//g; s/,//g'
Now what this does is
Print your package json
Search for the lines with "version"
Take only the first result
Replace " and ,
Please not that i have my scripts in a subfolder with the according name in my repository. So if you don't change $BASEDIR/../package.json to $BASEDIR/package.json
Or if you want to be able to get major, minor and patch version I use this
scripts/getCurrentVersion.sh
VERSION_TYPE=$1
BASEDIR=$(dirname $0)
VERSION=$(cat $BASEDIR/../package.json | grep '"version"' | head -n 1 | awk '{print $2}' | sed 's/"//g; s/,//g')
if [ $VERSION_TYPE = "major" ]; then
echo $(echo $VERSION | awk -F "." '{print $1}' )
elif [ $VERSION_TYPE = "minor" ]; then
echo $(echo $VERSION | awk -F "." '{print $1"."$2}' )
else
echo $VERSION
fi
this way if your version was 1.2.3. Your output would look like this
$ > sh ./getCurrentVersion.sh major
1
$> sh ./getCurrentVersion.sh minor
1.2
$> sh ./getCurrentVersion.sh
1.2.3
Now the only thing you will have to make sure is that your package version will be the first time in package.json that key is used otherwise you'll end up with the wrong version
I'm using create-react-app and I don't have process.env.npm_package_version available when executing my React-app.
I did not want to reference package.json in my client-code (because of exposing dangerous info to client, like package-versions), neither I wanted to install an another dependency (genversion).
I found out that I can reference version within package.json, by using $npm_package_version in my package.json:
"scripts": {
"my_build_script": "REACT_APP_VERSION=$npm_package_version react-scripts start"
}
Now the version is always following the one in package.json.
I made a useful code to get the parent module's package.json
function loadParentPackageJson() {
if (!module.parent || !module.parent.filename) return null
let dir = path.dirname(module.parent.filename)
let maxDepth = 5
let packageJson = null
while (maxDepth > 0) {
const packageJsonPath = `${dir}/package.json`
const exists = existsSync(packageJsonPath)
if (exists) {
packageJson = require(packageJsonPath)
break
}
dir = path.resolve(dir, '../')
maxDepth--
}
return packageJson
}
If using rollup, the rollup-plugin-replace plugin can be used to add the version without exposing package.json to the client.
// rollup.config.js
import pkg from './package.json';
import { terser } from "rollup-plugin-terser";
import resolve from 'rollup-plugin-node-resolve';
import commonJS from 'rollup-plugin-commonjs'
import replace from 'rollup-plugin-replace';
export default {
plugins: [
replace({
exclude: 'node_modules/**',
'MY_PACKAGE_JSON_VERSION': pkg.version, // will replace 'MY_PACKAGE_JSON_VERSION' with package.json version throughout source code
}),
]
};
Then, in the source code, anywhere where you want to have the package.json version, you would use the string 'MY_PACKAGE_JSON_VERSION'.
// src/index.js
export const packageVersion = 'MY_PACKAGE_JSON_VERSION' // replaced with actual version number in rollup.config.js
const { version } = require("./package.json");
console.log(version);
const v = require("./package.json").version;
console.log(v);
Import your package.json file into your server.js or app.js and then access package.json properties into server file.
var package = require('./package.json');
package variable contains all the data in package.json.
Used to version web-components like this:
const { version } = require('../package.json')
class Widget extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
}
public connectedCallback(): void {
this.renderWidget()
}
public renderWidget = (): void => {
this.shadowRoot?.appendChild(this.setPageTemplate())
this.setAttribute('version', version)
}
}

Usage of Bazel to build polyglot projects

I have a Kotlin JVM project that runs some JavaScript in an native runtime. Currently, the different language sources are defined in separate repositories and the JS file is webpacked and packaged as a JAR to be specified as a dependency of the JVM project. This works fine, but I want to merge the two repositories as they are inherently coupled. Rather than maintain an abundance of different build tooling, I thought it would be a good opportunity to learn and use a polyglot build system, like Bazel.
The current structure:
Essentially, there are two main packages I'm trying to build. The web package builds correctly and I can view the webpacked output via command line. Including the web BUILD file for full picture:
load("#npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "compileCore",
srcs = ["index.ts"],
tsconfig = "tsconfig.json",
)
filegroup(
name = "internalCore",
srcs = ["compileCore"],
output_group = "es5_sources",
)
load("#npm//webpack-cli:index.bzl", webpack = "webpack_cli")
webpack(
name = "bundle",
outs = ["bundle.prod.js"],
args = [
"--mode production",
"$(execpath internalCore)",
"--config",
"$(execpath webpack.config.js)",
"-o",
"$#",
],
data = [
"internalCore",
"webpack.config.js",
"#npm//:node_modules",
],
visibility = ["//visibility:public"],
)
The other important package is the nested //jvm/src/main/java/com/example/bazel/plugin package. This is essentially the final deliverable, which should be a JAR with the output of the web package included as resources.
load("#io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
kt_jvm_library(
name = "plugin",
srcs = glob(["*.kt"]),
deps = [
# ... some deps
],
resources = ["//web:bundle"],
visibility = ["//visibility:public"],
)
This is seemingly straightforward, but errors during the build with:
❯ bazel build //jvm/src/...
INFO: Analyzed target //jvm/src/main/java/com/example/bazel/plugin:plugin (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
ERROR: /Users/jzucker/dev/GitHub/plugin-example-bazel/jvm/src/main/java/com/example/bazel/plugin/BUILD:12:15: error executing shell command: '/bin/bash -c external/bazel_tools/tools/zip/zipper/zipper c bazel-out/darwin-fastbuild/bin/jvm/src/main/java/com/example/bazel/plugin/plugin-resources.jar #bazel-out/darwin-fastbuild/bin/jvm/src/ma...' failed (Exit 255) bash failed: error executing command /bin/bash -c ... (remaining 1 argument(s) skipped)
Use --sandbox_debug to see verbose messages from the sandbox
File web/bundle.prod.js does not seem to exist.Target //jvm/src/main/java/com/example/bazel/plugin:plugin failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 0.402s, Critical Path: 0.05s
INFO: 0 processes.
FAILED: Build did NOT complete successfully
After some experimentation, this seems to be an issue of trying to bundle generated outputs as resources for a kt_jvm_library. If the resources reference a tangible source file from another package, then it works just fine. The main question here is whether this is the right pattern for Bazel or if I'm trying to abuse this technology. This seems like a relatively simple use case, but there is a line in the docs that concerns me the most:
An invariant of all rules is that the files generated by a rule always belong to the same package as the rule itself; it is not possible to generate files into another package. It is not uncommon for a rule's inputs to come from another package, though.
From https://docs.bazel.build/versions/master/build-ref.html
Any insight would be greatly appreciated.
This is actually a bug in the Bazel Kotlin ruleset:
github.com/bazelbuild/rules_kotlin/issues/281
Until that is fixed, you can package the resources in a java_library and include that as resource_jars.
java_library(
name = "resources",
resources = ["//web:bundle"],
resource_strip_prefix = "web",
)
load("#io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
kt_jvm_library(
name = "plugin",
srcs = glob(["*.kt"]),
deps = [
# ... some deps
],
resource_jars = ["resources"],
visibility = ["//visibility:public"],
)

ember build command fails with error: no such file or directory, lstat ..../ember-cli-test-loader/test-loader

I have recently updated the dependencies in packages.json and bower.json and have run into a similar error like this that i solved by providing an overwrite to the vendorFiles option in my EmberApp:
## ember-cli-build.js
...
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
vendorFiles: {
'ember-resolver.js': [
'bower_components/ember-resolver/index.js' , { //similar error to below was solved like this
exports: {
'ember/resolver': ['default']
}
}
],
...
}
});
...
I have tried a similar solution where I place this code in the vendorFiles property to no good luck :( :
#ember-cli-build.js
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
vendorFiles: {
'ember-resolver.js': <...>,
// \/\/\/\/\/\/\/\/\/
'ember-cli-test-loader': [
'bower_components/ember-cli-test-loader/index.js', {
exports: {
'ember/test-loader': ['default']
}
}
]
// /\/\/\/\/\/\/\/\/\
}
});
Full output as follows:
ENOENT: no such file or directory, lstat '<...>/my-app/tmp/funnel-input_base_path-qUHHutHN.tmp/0/bower_components/ember-cli-test-loader/test-loader.js'
Error: ENOENT: no such file or directory, lstat '<...>/my-app/tmp/funnel-input_base_path-qUHHutHN.tmp/0/bower_components/ember-cli-test-loader/test-loader.js'
at Error (native)
at Object.fs.lstatSync (fs.js:839:18)
at symlink (<...>/my-app/node_modules/ember-cli/node_modules/symlink-or-copy/index.js:63:26)
at Function.symlinkOrCopySync [as sync] (<...>/my-app/node_modules/ember-cli/node_modules/symlink-or-copy/index.js:58:5)
at Funnel._copy (<...>/my-app/node_modules/ember-cli/node_modules/broccoli-funnel/index.js:398:19)
at Funnel.processFile (<...>/my-app/node_modules/ember-cli/node_modules/broccoli-funnel/index.js:381:8)
at Funnel.applyPatch [as _applyPatch] (<...>/my-app/node_modules/ember-cli/node_modules/broccoli-funnel/index.js:298:12)
at Funnel.<anonymous> (<...>/my-app/node_modules/ember-cli/node_modules/broccoli-funnel/index.js:250:10)
at Array.forEach (native)
at Funnel.processFilters (<...>/my-app/node_modules/ember-cli/node_modules/broccoli-funnel/index.js:249:9)
I'm not sure from the output where i would find out what is happening. I'm new to broccoli (coming from grunt and gulp) and also new to ember-cli
If you look at the Releases, you will notice that the Latest release is set to 0.2.2
It works fine if you use 0.2.2 (and not 1.0.0).
I submitted an issue regarding this.
I Believe I've answered my own question:
The version of test-loader I have is 1.0.0. When i looked at the actual files, the index.js is quite bare. I don't know why the owner of this library tagged it as 1.0.0 as it does not do much... (well I suppose it is a "breaking change" technically speaking)
Anyway, I reverted my version to 0.1.3 and it seems to work now. Also i had to get rid of the test-loader portion in my vendorFiles option as i no longer needed it.
Thanks for considering my question!
Run the command inside project folder:
D:\Latest\eswari\develop-16.2.1\jefferson>bower install --save ember-cli-test-loader#0.1.3
The ember-cli-test-loader package is no longer explicitly required by your package.json or bower.json files. Likely reason you are seeing the error today is outdated dependencies in your project.

Coffeeify won't parse more than the entry file

I'm quite a beginner with Browserify. I tried to integrate it into gulp.js with Watchify (for performance reasons) and Coffeeify. I tried at least five more or less different approaches I found in Google, the last of them being an official recipe from the gulp docs.
Problem now is the transforming part. I want to use Coffeeify to parse my code which is mostly written in CoffeeScript.
Coffeeify successfully parses my entry file app.coffee but when I require a ./foo.coffee from there, that file seems not to be transformed which will naturally result in a parsing error by Browserify about unexpected tokens etc.
Anyone got an idea how to fix that?
Here's the relevant part of my gulpfile, mostly the same as in the link above, just with added transformations.
var gulp = require( 'gulp' );
var gutil = require( 'gulp-util' );
var browserify = require( 'browserify' );
var watchify = require( 'watchify' );
var coffeeify = require( 'coffeeify' );
var source = require( 'vinyl-source-stream' );
var b = watchify( browserify({
entries: [ './coffee/app.coffee' ],
extensions: [ '.coffee' ],
debug: true,
cache: false,
packageCache: false
}) );
b.transform( coffeeify ); // as described in the gulp docs
gulp.task( 'bundle', bundle );
b.on( 'update', bundle );
b.on( 'log', gutil.log );
function bundle() {
return b.bundle()
.on( 'error', gutil.log.bind( gutil, 'Browserify Error' ) )
.pipe( source( 'bundle.js' ) )
// I actually tried to pipe in coffeeify here (gulp-coffeeify as well), didn't help
.pipe( gulp.dest( './js' ) );
};
Okay, this was totally my bad. I abstracted my code a bit too far for this post so the actual problem wasn't reflected here:
app.coffee does not actually require ./foo.coffee directly but requires foo/foo from a node_modules directory, just to make things easier.
Which was exactly the problem: Transforms will not apply to required packages. This is intended behavior.
There seem to be two ways around that:
Solution 1: A browserify option called global-transform.
In the API it's used like b.transform( coffeeify, { global: true } ). This will apply the coffeeify transform to every required module.
Solution 2: Package-wise definition of transforms. That means: Adding something like this to each modules' package.json:
{
"browserify": {
"transform": ["coffeeify"]
}
}
I decided to use the first one because my "packages" actually don't even have a package.json file, they're just in the node_modules directory to be easily accessible by browserify.

Categories