16

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.

tk421
  • 5,775
  • 6
  • 23
  • 34
Luiz Guilherme
  • 1,601
  • 21
  • 37

3 Answers3

1

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:

  1. copy the yarn.lock file and the root package.json

  2. 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).

  3. in the dockerfile, manually remove all the devDependnecies of all the package.json(s) that you copied.

  4. run yarn install on the root package.json.

Note:

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()
}
Stav Alfi
  • 13,139
  • 23
  • 99
  • 171
-1

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).

Leksat
  • 2,923
  • 1
  • 27
  • 26
-2

You may try

yarn workspace @my-monorepo/my-package-in-workspace install -- --prod

Boloss
  • 1