Yarn install production dependencies of a single package in workspace - node.js

I'm trying to install the production dependencies only for a single package in my workspace. Is that possible?
I've already tried this:
yarn workspace my-package-in-workspace install -- --prod
But it is installing all production dependencies of all my packages.

yarn 1 doesn't support it as far as I know.
If you are trying to install a specific package in a dockerfile, then there is a workaround:
copy the yarn.lock file and the root package.json
copy only the packages's package.json that you need: your package and which other packages that your package depends on (locally in the monorepo).
in the dockerfile, manually remove all the devDependnecies of all the package.json(s) that you copied.
run yarn install on the root package.json.
Note:
Deterministic installation - It is recommended to do so in monorepos to force deterministic install - https://stackoverflow.com/a/64503207/806963
Full dockefile example:
FROM node:12
WORKDIR /usr/project
COPY yarn.lock package.json remove-all-dev-deps-from-all-package-jsons.js change-version.js ./
ARG package_path=packages/dancer-placing-manager
COPY ${package_path}/package.json ./${package_path}/package.json
RUN node remove-all-dev-deps-from-all-package-jsons.js && rm remove-all-dev-deps-from-all-package-jsons.js
RUN yarn install --frozen-lockfile --production
COPY ${package_path}/dist/src ./${package_path}/dist/src
COPY ${package_path}/src ./${package_path}/src
CMD node --unhandled-rejections=strict ./packages/dancer-placing-manager/dist/src/index.js
remove-all-dev-deps-from-all-package-jsons.js:
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
async function deleteDevDeps(packageJsonPath) {
const packageJson = require(packageJsonPath)
delete packageJson.devDependencies
await new Promise((res, rej) =>
fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8', error => (error ? rej(error) : res())),
)
}
function getSubPackagesPaths(repoPath) {
const result = execSync(`yarn workspaces --json info`).toString()
const workspacesInfo = JSON.parse(JSON.parse(result).data)
return Object.values(workspacesInfo)
.map(workspaceInfo => workspaceInfo.location)
.map(packagePath => path.join(repoPath, packagePath, 'package.json'))
}
async function main() {
const repoPath = __dirname
const packageJsonPath = path.join(repoPath, 'package.json')
await deleteDevDeps(packageJsonPath)
await Promise.all(getSubPackagesPaths(repoPath).map(packageJsonPath => deleteDevDeps(packageJsonPath)))
}
if (require.main === module) {
main()
}

It looks like this is easily possible now with Yarn 2: https://yarnpkg.com/cli/workspaces/focus
But I haven't tried myself.
Here is my solution for Yarn 1:
# Install dependencies for the whole monorepo because
# 1. The --ignore-workspaces flag is not implemented https://github.com/yarnpkg/yarn/issues/4099
# 2. The --focus flag is broken https://github.com/yarnpkg/yarn/issues/6715
# Avoid the target workspace dependencies to land in the root node_modules.
sed -i 's|"dependencies":|"workspaces": { "nohoist": ["**"] }, "dependencies":|g' apps/target-app/package.json
# Run `yarn install` twice to workaround https://github.com/yarnpkg/yarn/issues/6988
yarn || yarn
# Find all linked node_modules and dereference them so that there are no broken
# symlinks if the target-app is copied somewhere. (Don't use
# `cp -rL apps/target-app some/destination` because then it also dereferences
# node_modules/.bin/* and thus breaks them.)
cd apps/target-app/node_modules
for f in $(find . -maxdepth 1 -type l)
do
l=$(readlink -f $f) && rm $f && cp -rf $l $f
done
Now apps/target-app can be copied and used as a standalone app.
I would not recommend it for production. It is slow (because it installs dependencies for the whole monorepo) and not really reliable (because there may be additional issues with symlinks).

You may try
yarn workspace #my-monorepo/my-package-in-workspace install -- --prod

Related

How can I connect to Memgraph database and executes queries using Rust?

I'm starting to learn Rust. I want to try out connecting to the Memgraph database and executing a query. I'm running a local instance of Memgraph Platform in Docker. I'm running it with default settings.
Since you are using Docker right after you create a new Rust project using cargo new memgraph_rust --bin add the following line to the Cargo.toml file under the line [dependencies] :
rsmgclient = "1.0.0"
Then, add the following code to the src/main.rs file:
use rsmgclient::{ConnectParams, Connection, SSLMode};
fn main(){
// Parameters for connecting to database.
let connect_params = ConnectParams {
host: Some(String::from("172.17.0.2")),
sslmode: SSLMode::Disable,
..Default::default()
};
// Make a connection to the database.
let mut connection = match Connection::connect(&connect_params) {
Ok(c) => c,
Err(err) => panic!("{}", err)
};
// Execute a query.
let query = "CREATE (u:User {name: 'Alice'})-[:Likes]->(m:Software {name: 'Memgraph'}) RETURN u, m";
match connection.execute(query, None) {
Ok(columns) => println!("Columns: {}", columns.join(", ")),
Err(err) => panic!("{}", err)
};
// Fetch all query results.
match connection.fetchall() {
Ok(records) => {
for value in &records[0].values {
println!("{}", value);
}
},
Err(err) => panic!("{}", err)
};
// Commit any pending transaction to the database.
match connection.commit() {
Ok(()) => {},
Err(err) => panic!("{}", err)
};
}
Now, create a new file in the project root directory /memgraph_rust and name it Dockerfile:
# Set base image (host OS)
FROM rust:1.56
# Install CMake
RUN apt-get update && \
apt-get --yes install cmake
# Install mgclient
RUN apt-get install -y git cmake make gcc g++ libssl-dev clang && \
git clone https://github.com/memgraph/mgclient.git /mgclient && \
cd mgclient && \
git checkout 5ae69ea4774e9b525a2be0c9fc25fb83490f13bb && \
mkdir build && \
cd build && \
cmake .. && \
make && \
make install
# Set the working directory in the container
WORKDIR /code
# Copy the dependencies file to the working directory
COPY Cargo.toml .
# Copy the content of the local src directory to the working directory
RUN mkdir src
COPY src/ ./src
# Generate binary using the Rust compiler
RUN cargo build
# Command to run on container start
CMD [ "cargo", "run" ]
All that is now left is to get the address docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' CONTAINER_ID, create and image docker build -t memgraph_rust . and starting the application with docker run memgraph_rust.
If you ever decide to take your Rust program to an environment that doesn't have Docker you will maybe need to install rsmgclient driver
The complete documentation for connecting using Rust can be found at Rust quick start guide on the Memgraph site.

Running npm install with sbt

So I have a sbt project that uses sbt-js-engine and sbt-webpack plugins.
It successfully gets and resolves npm packages just fine. And then webpack would build the project.
I have added a npm install script into package.json like so,
"scripts": {
"install": "bower install"
}
However, the problem I am currently having is that when I run webpack (which intern uses sbt-js-engine ) it runs npm update instead of npm install.
Heres an excerpt of my build.sbt,
lazy val common = project.in(file("common")).
enablePlugins(SbtWeb).
settings(
sourceDirectory in webpack := baseDirectory.value,
resourceManaged in webpack := (resourceManaged in webpack in root).value,
includeFilter in webpack := ("*.jsx" || "*.js" || "*.json") && new FileFilter {
#tailrec
override def accept(pathname: File): Boolean = {
if (pathname == null) false
else if (pathname.getName == "javascripts") true
else accept(pathname.getParentFile)
}
},
JsEngineKeys.engineType := JsEngineKeys.EngineType.Node
)
Is there anyway I could run npm install instead or even before as a depedency for webpack task ?
You could try something like this:
sourceDirectory in webpack := {
Process("/usr/local/bin/npm install", file("[path to working dir]")).!
baseDirectory.value
}
That would mean it would run at same time as setting the webpack settings.

Grunt and NPM, package all production dependencies

I am unsure when the way the NPM installs dependencies changed.
In the past I remember that if in my project.json I had a dependency on "abc", which in turn would depend on "xyz", a npm install would result in something like:
package.json
node_modules/
abc/
node_modules/
xyz/
some-dev-dep/
When packaging my node project to be used by AWS Lambda, I would have to include that node_modules structure (less any dev-dependencies that were there). I would use Grunt for my packaging, so I wrote this handy thing to help me get all production dependencies into this zip (extracting part of my gruntfile.js):
function getDependencies(pkg) {
return Object.keys(pkg.dependencies)
.map(function(val) { return val + '/**'; });
}
var config = {
compress: {
prod: {
options: {
archive: 'public/lambda.zip'
},
files: [
{ src: 'index.js', dest: '/' },
{ expand: true, cwd: 'node_modules/', src: getDependencies(pkg), dest: '/node_modules' }
]
}
}
};
This would work because dependencies of my dependencies were nested.
Recently (or maybe not-so-recently) this has changed (I am unsure when as I was using very old version of NPM and updated it recently).
Now if I depend on "abc" which in turn depends on "xyz" I will get:
node_modules/
abc/
xyz/
some-dev-dep/
As you can see, my way of getting only production dependencies just won't work.
Is there any easy way to get only list of production dependencies (together with sub-dependencies) within grunt job?
I could do it using recursive function scanning for my dependencies, and then checking project.json files of those and then searching for sub-dependencies etc. This approach seems like a lot of hassle that is possibly a common scenario for many projects...
Here is a function that returns an array of the production dependency module names. (Note: you might need to have the 'npm' module installed locally in your project for this to work.)
/**
* Returns an array of the node dependencies needed for production.
* See https://docs.npmjs.com/cli/ls for info on the 'npm ls' command.
*/
var getProdDependencies = function(callback) {
require('child_process').exec('npm ls --prod=true --parseable=true', undefined,
function(err, stdout, stderr) {
var array = stdout.split('\n');
var nodeModuleNames = [];
array.forEach(function(line) {
var index = line.indexOf('node_modules');
if (index > -1) {
nodeModuleNames.push(line.substr(index + 13));
}
});
callback(nodeModuleNames);
});
};
This change was introduced with the release of npm 3 (see npm v3 Dependency Resolution).
It's not exactly clear why you need to use Grunt at all. If what you want to do is get only production dependencies you can simply run:
npm install --production
With the --production flag, all dev dependencies will be ignored. The same is also true if the NODE_ENV environment variable is set to 'production'.

How quickly check whether to run npm install Node

Next script goes thought all folders and installs dependencies
var fs = require( "fs" ),
path = require( "path" ),
child_process = require( "child_process" );
var rootPath = "./";
var dirs = fs.readdirSync( rootPath )
.filter( function( dir ) {
return fs.statSync( path.join( rootPath, dir )).isDirectory();
});
var install = function()
{
if ( dirs.length === 0 )
return;
var dir = dirs.shift();
console.log( "installing dependencies for : '" + dir + "'" );
child_process.exec( "npm prune --production | npm install", {
cwd: rootPath + dir
}, install );
};
install();
How to run npm install command only if package.json exists in folder?
Try this command:
ls | grep package.json && (npm prune --production | npm install)
I assume you are running this in Linux.
In theory, if I remember correctly, the ouput of the command ls will be piped to the grep command, and only if the grep command will have found a result, then the commands (npm prune --production | npm install) will be executed.
This is not tested by me at the moment of writting this, since I don't have a Linux box right now to test this, but I hope it works.
UPDATE:
The efficient command, as per Dan's comment would be
test -f package.json && (npm prune --production | npm install)

How do I npm install for current directory and also subdirectories with package.json files?

I have a an application which is a web game server and say for example I have node_modules which I use in directory ./ and I have a proper package.json for those. it happens that in directory ./public/ I have a website being served which itself uses node_modules and also has a proper package.json for itself.
I know I can do this by navigating the directories. But is there a command or way to automate this so that it is easier for other developers to bootstrap the application in their system?
Assuming you are on Linux/OSX, you could try something like this:
find ./apps/* -maxdepth 1 -name package.json -execdir npm install \;
Arguments:
./apps/* - the path to search. I would advise being very specific here to avoid it picking up package.json files in other node_modules directories (see maxdepth below).
-maxdepth 1 - Only traverse a depth of 1 (i.e. the current directory - don't go into subdirectories) in the search path
-name package.json - the filename to match in the search
-execdir npm install \; - for each result in the search, run npm install in the directory that holds the file (in this case package.json). Note that the backslash escaping the semicolon has to be escaped itself in the JSON file.
Put this in the postinstall hook in your root package.json and it will run everytime you do an npm install:
"scripts": {
"postinstall": "find ./apps/* -name package.json -maxdepth 1 -execdir npm install \\;"
}
For cross-platform support (incl. Windows) you may try my solution.
Pure Node.js
Run it as a "preinstall" npm script
const path = require('path')
const fs = require('fs')
const child_process = require('child_process')
const root = process.cwd()
npm_install_recursive(root)
function npm_install_recursive(folder)
{
const has_package_json = fs.existsSync(path.join(folder, 'package.json'))
if (!has_package_json && path.basename(folder) !== 'code')
{
return
}
// Since this script is intended to be run as a "preinstall" command,
// skip the root folder, because it will be `npm install`ed in the end.
if (has_package_json)
{
if (folder === root)
{
console.log('===================================================================')
console.log(`Performing "npm install" inside root folder`)
console.log('===================================================================')
}
else
{
console.log('===================================================================')
console.log(`Performing "npm install" inside ${folder === root ? 'root folder' : './' + path.relative(root, folder)}`)
console.log('===================================================================')
}
npm_install(folder)
}
for (let subfolder of subfolders(folder))
{
npm_install_recursive(subfolder)
}
}
function npm_install(where)
{
child_process.execSync('npm install', { cwd: where, env: process.env, stdio: 'inherit' })
}
function subfolders(folder)
{
return fs.readdirSync(folder)
.filter(subfolder => fs.statSync(path.join(folder, subfolder)).isDirectory())
.filter(subfolder => subfolder !== 'node_modules' && subfolder[0] !== '.')
.map(subfolder => path.join(folder, subfolder))
}

Resources