Search code examples
node.jsdockernode-modulesyarnpkgmonorepo

yarn: install local package from monorepo and use it inside docker image with offline cache


My folder structure looks like this (monorepo):

project
|
+--- /api
|    |
|    +--- /.offline-cache
|    +--- /src
|    |    +--- index.js
|    |    +--- ...
|    |
|    +--- Dockerfile
|    +--- package.json
|    +--- yarn.lock
|
+--- /common
|    |
|    +--- /src
|    |    +--- index.js
|    |
|    +--- package.json
|
+--- /ui
|    |
|    +--- /.offline-cache
|    +--- /src
|    |    +--- index.js
|    |    +--- ...
|    |
|    +--- Dockerfile
|    +--- package.json
|    +--- yarn.lock
|
+--- docker-compose.yml

The offline-cache and building the docker-images for every 'service' (ui, api) are working.

Now I want to access/install the common module inside api and ui as well.
Running yarn add ./../common inside /api works and installs the module inside the api folder and adds it to package.json and yarn.lock file. But when I try to rebuild the docker-image I get an error telling me

error Package "" refers to a non-existing file '"/common"'.

That's because there is no common folder inside the docker container and the installed package isn't added to the offline-mirror :(

I can't copy the common folder to the docker-image because it is outside the build context and I don't want to publish to NPM. What else can I do to get this working?


Solution

  • You can specify a context in your docker-compose.yml, which does not need to be the same directory as your Dockerfile.

    So you can create something like this:

    version: '3.5'
    
    services:
      ui:
        build:
          context: .
          dockerfile: ui/Dockerfile
        ports:
          - 'xxxx:xxxx'
    
      api:
        build:
          context: .
          dockerfile: api/Dockerfile
        ports:
          - 'xxxx:xxxx'
    

    The same thing can be done with docker build as well, by adding the -f option, while running the command from the root directory.

    docker build -f ui/Dockerfile xxxxxx/ui .
    
    docker build -f api/Dockerfile xxxxxx/api .
    

    You need to be aware, that you have to modify your Dockerfile slightly as well, to match the file structure of the project (using WORKDIR).

    FROM node:18-alpine
    
    # switch to root and copy all relevant files
    WORKDIR /app
    COPY ./ui/ ./ui/
    COPY ./common/ ./common/
    
    # switch to relevant path (in this case ui)
    WORKDIR /app/ui
    RUN yarn && yarn build
    
    CMD ["yarn", "start"]