I am following Node.js's "Intro to Docker" tutorial and, when I run npm start, the project works. When I run docker run (options), the build is generated, but I'll find the error below in the logs. The project is bare-bones, simple, and straight-forward, I'm not sure what I'm missing here. I've gotten a very similar error in production earlier (to Heroku, without Docker), where local runs look good and live deploys get a similar error.
I'm not sure if I'm using something outdated, but I updated npm, docker, and am not sure what else could be.
Any help is appreciated!
Error:
internal/modules/cjs/loader.js:969
throw err;
^
Error: Cannot find module '/usr/src/app/server.js'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:966:15)
at Function.Module._load (internal/modules/cjs/loader.js:842:27)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Directory:
package.json:
{
"name": "SampleProject",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "First Last <first.last#example.com>",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dock": "docker run -p 1234:1234 -d <My>/<Info>"
},
"dependencies": {
"core-util-is": "^1.0.2",
"express": "^4.17.1"
}
}
Dockerfile
# I'm using Node.js -> Import it's image
FROM node:12
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm#5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Run on port 1234
EXPOSE 1234
CMD [ "node", "server.js" ]
server.js
'use strict';
const express = require('express');
// Constants
const PORT = 1234;
const HOST = '0.0.0.0';
// App
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
Run:
npm run dock
Note:
I've also cleaned out the project by running the following:
rm -rf node_modules package-lock.json && npm install && npm start
RESOLVED:
Dockerfile
# I'm using Node.js -> Import it's image
FROM node:12
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm#5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# * BEGIN SOLUTION *
# Bundle app source
COPY . .
# * END SOLUTION *
# Run on port 1234
EXPOSE 1234
CMD [ "node", "server.js" ]
I think you are missing the following important part, should be placed after you have RUN npm install:
To bundle your app's source code inside the docker image, use the COPY instruction:
# Bundle app source
COPY . .
And to force the execution of each step in the Dockerfile,
docker build --no-cache
Related
Did a docker-compose up to build my project, but there's something wrong and I am getting this error:
node:internal/errors:464
ErrorCaptureStackTrace(err);
^
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/parser' is not defined by "exports" in /usr/app/node_modules/postcss/package.json
at new NodeError (node:internal/errors:371:5)
at throwExportsNotFound (node:internal/modules/esm/resolve:429:9)
at packageExportsResolve (node:internal/modules/esm/resolve:703:3)
at resolveExports (node:internal/modules/cjs/loader:482:36)
at Function.Module._findPath (node:internal/modules/cjs/loader:522:31)
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.552 (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:11590)
at __nccwpck_require__ (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:11735)
at Object.270 (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:400)
at __nccwpck_require__ (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:11735)
at Object.327 (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:260)
at __nccwpck_require__ (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:11735)
at Object.845 (/usr/app/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:3733) {
code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Node.js v17.4.0
Service 'nextjs' failed to build : The command '/bin/sh -c npm run build' returned a non-zero code: 1
Here's my Dockerfile
FROM node:alpine
# Set working directory
WORKDIR /usr/app
# Install PM2 globally
RUN npm install --global pm2
# Copy "package.json" and "package-lock.json" before other files
# Utilise Docker cache to save re-installing dependencies if unchanged
COPY ./package*.json ./
# Install dependencies
RUN npm install --production
# Copy all files
COPY ./ ./
# Build app
RUN npm run build
# Expose the listening port
EXPOSE 3000
# Run container as non-root (unprivileged) user
# The "node" user is provided in the Node.js Alpine base image
USER node
# Launch app with PM2
CMD [ "pm2-runtime", "start", "npm", "--", "start" ]
Here's my package.json:
{
"name": "nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^10.0.6",
"react": "17.0.1",
"react-dom": "17.0.1"
}
}
Tried deleting my node_modules folder and reinstalling, but it doesn't work. What's using the post/css package and is the error due to the node version? If so, what alpine version should I use in my Dockerfile?
I guess am late , but I have the solution.
I faced the same issue you were facing in this line
import { useState } from "react/cjs/react.production.min";
You should try this instead...
import {useState} from 'react' directly
I am trying to dockerize a Vite React-Typescript boilerplate setup, but I unable to connect to the container.
Installed vite-react-typescript boilerplate:
npm init vite#latest vite-docker-demo -- --template react-ts
Dockerfile
# Declare the base image
FROM node:lts-alpine3.14
# Build step
# 1. copy package.json and package-lock.json to /app dir
RUN mkdir /app
COPY package*.json /app
# 2. Change working directory to newly created app dir
WORKDIR /app
# 3 . Install dependencies
RUN npm ci
# 4. Copy the source code to /app dir
COPY . .
# 5. Expose port 3000 on the container
EXPOSE 3000
# 6. Run the app
CMD ["npm", "run", "dev"]
Command to run docker container in detached mode and open local dev port 3000 on host:
docker run -d -p 3000:3000 vite
The vite instance seems to be running just fine within the container (docker logs output):
> vite-docker#0.0.0 dev /app
> vite
Pre-bundling dependencies:
react
react-dom
(this will be run only when your dependencies or config have changed)
vite v2.4.4 dev server running at:
> Local: http://localhost:3000/
> Network: use `--host` to expose
ready in 244ms.
However, when I navigate to http://localhost:3000/ within Chrome. I see an error indicating The connection was reset.
Any help resolving this issue would be greatly appreciated!
It turns out that I needed to configure host to something other than localhost.
Within vite.config.ts:
import { defineConfig } from 'vite'
import reactRefresh from '#vitejs/plugin-react-refresh'
// https://vitejs.dev/config/
export default defineConfig({
server: {
host: '0.0.0.0',
port: 3000,
},
plugins: [reactRefresh()],
})
Resolves the issue.
in package.json use script
"dev": "vite --host"
example:
"scripts": {
"dev": "vite --host",
"build": "tsc && vite build",
"serve": "vite preview"
},
or run with vite --host
To use hot reload, so the changes actually get reflected:
export default (conf: any) => {
return defineConfig({
server: {
host: "0.0.0.0",
hmr: {
clientPort: ENV_VARIABLES.OUTER_PORT_FRONTEND,
},
port: ENV_VARIABLES.INNER_PORT_FRONTEND_DEV,
watch: {
usePolling: true,
},
},
});
};
I am playing with Docker to create a small node app image and I would like to get rid of the warning below:
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN webserver#1.0.0 No description
npm WARN webserver#1.0.0 No repository field.
when building my image
PS C:\Users\eperret\Desktop\webserver> docker build .
Sending build context to Docker daemon 4.096kB
Step 1/5 : FROM node:alpine
---> cd4fae427afc
Step 2/5 : COPY ./package.json ./
---> 990e1ee0398d
Step 3/5 : RUN npm install
---> Running in 8ffb61d273e4
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN webserver#1.0.0 No description
npm WARN webserver#1.0.0 No repository field.
added 48 packages from 36 contributors and audited 121 packages in 1.675s
found 0 vulnerabilities
Removing intermediate container 8ffb61d273e4
---> fff34a1d0b4e
Step 4/5 : COPY ./ ./
---> ace2bc83a3f9
Step 5/5 : CMD [ "npm", "start" ]
---> Running in fa9d0a961867
Removing intermediate container fa9d0a961867
---> 34a593a4b338
Successfully built 34a593a4b338
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
My Dockerfile
FROM node:alpine
COPY ./package.json ./
RUN npm install
COPY ./ ./
CMD [ "npm", "start" ]
//Load express module with `require` directive
var express = require('express')
var app = express()
//Define request response in root URL (/)
app.get('/', (req, res) => {
res.send('How are you doing');
});
//Launch listening server on port 8081
app.listen(8080, () => {
console.log('Listening on port 8080');
});
and package.json:
{
"name": "webserver",
"version": "1.0.0",
"description": "",
"repository": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "*"
}
}
I also think it's kinda weird that there is also a warning about the lack description and repository fields since both are present in my package.json above.
According to the answer here
I can disable package-lock.json globally in the intermediate container:
RUN npm config set package-lock false
FROM node:alpine
COPY ./package.json ./
RUN npm config set package-lock false
RUN npm install
COPY ./ ./
CMD [ "npm", "start" ]
Which now outputs:
PS C:\Users\eperret\Desktop\webserver> docker build .
Sending build context to Docker daemon 4.096kB
Step 1/6 : FROM node:alpine
---> cd4fae427afc
Step 2/6 : COPY ./package.json ./
---> Using cache
---> 94e9c22361a2
Step 3/6 : RUN npm config set package-lock false
---> Using cache
---> 8d3df1028a80
Step 4/6 : RUN npm install
---> Using cache
---> 254d4ccce8ac
Step 5/6 : COPY ./ ./
---> Using cache
---> 48a1990903a6
Step 6/6 : CMD [ "npm", "start" ]
---> Using cache
---> 53cf819f42e7
Successfully built 53cf819f42e7
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
You should not use your time for something like this. It is a good idea to add package-lock.json file when building your application. If you REALLY want to not provide this file, just ignore the warning message.
I am trying to learn Docker and Docker Compose to set up a small example node/express server. I am running Docker toolbox on Windows 10 Home. Below is my project structure
root/
docker-compose.yml
Dockerfile
index.js
package.json
This is my Dockerfile
FROM node:8
WORKDIR /usr/app
COPY . .
RUN npm install --quiet
This is my docker-compose.yml
version: "2"
services:
node:
build: .
working_dir: /usr/app
environment:
- NODE_ENV=production
expose:
- "3000:3000"
command: "node index.js"
This is my package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
}
}
and this is my index.js
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I have mixed together various examples found on docs for each of the components. But I couldn't get it to run. When I do docker-compose up I get the following :
$ docker-compose up
Building node
Step 1/5 : FROM node:8
8: Pulling from library/node
61be48634cb9: Pull complete
fa696905a590: Pull complete
b6dd2322bbef: Pull complete
32477089adb4: Pull complete
febe7209ec28: Pull complete
4364cbe57162: Pull complete
ace5c680ff94: Pull complete
4acd6a9b7a48: Pull complete
Digest: sha256:7b65413af120ec5328077775022c78101f103258a1876ec2f83890bce416e896
Status: Downloaded newer image for node:8
---> 82c0936c46c1
Step 2/5 : WORKDIR /usr/app
---> Running in 454ed6735e6e
Removing intermediate container 454ed6735e6e
---> 62d35be2db4c
Step 3/5 : COPY package.json .
---> fdbb25021d83
Step 4/5 : RUN npm install --quiet
---> Running in e535ef0bc18f
npm WARN test#1.0.0 No description
npm WARN test#1.0.0 No repository field.
added 48 packages from 36 contributors and audited 121 packages in 3.179s
found 0 vulnerabilities
Removing intermediate container e535ef0bc18f
---> 1a61e872c386
Step 5/5 : COPY . .
---> 56e765cf1c3c
Successfully built 56e765cf1c3c
Successfully tagged root_node:latest
WARNING: Image for service node was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating root_node_1 ... done
Attaching to root_node_1
node_1 | module.js:550
node_1 | throw err;
node_1 | ^
node_1 |
node_1 | Error: Cannot find module '/usr/app/index.js'
node_1 | at Function.Module._resolveFilename (module.js:548:15)
node_1 | at Function.Module._load (module.js:475:25)
node_1 | at Function.Module.runMain (module.js:694:10)
node_1 | at startup (bootstrap_node.js:204:16)
node_1 | at bootstrap_node.js:625:3
root_node_1 exited with code 1
I did come across my googling that there is some issue with Windows and file permissions but I couldn't find anything more detailed about this.
EDIT 1 : I have removed volume from docker-compose.yml and it works fine when I run with Docker CE for MacOS. The same thing cannot still find index.js in Windows with Docker tools
Would you please try the below.
In your index.js, expose port is 3000, so we will expose the same in the DockerFile.
In docker-compose.yml, 5000 to 3000 mapping of port is done. Where 5000 will be host (Windows) and 3000 client (Linux).
Dockerfile:
FROM node:8
WORKDIR /usr/app
COPY package.json .
RUN npm install --quiet
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "5000:3000"
I'm using Docker on windows for development purposes and i'm trying to create a simple workflow for a node.js project.
I followed this tutorial https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ so my Dockerfile looks like this
FROM node:boron
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
COPY package.json .
# For npm#5 or later, copy package-lock.json as well
# COPY package.json package-lock.json ./
RUN npm install
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]
My "workflow" for each change would look like this
FIRST BUILD
docker build -t thomas/myApp DockerProjects/myApp ; docker run --name app -p 49160:8080 -d thomas/myApp
AFTER EACH CHANGE
docker build -t thomas/myApp DockerProjects/myApp ; docker stop app ; docker rm app ; docker run --name app -p 49160:8080 -d thomas/myApp
I don't want to have hundreds of containers after each change in the project, that's why i'm deleting it before creating another one.
I see several problems:
Each time there is a change and a new image is build, a new <none>:<none> image is created. These images have the same weight as the original one. How can I avoid that ?
Can I use nodemon somehow ?
Can I launch this process automatically each time I change something in the code ?
Docker is quite new for me and i'm still experimenting with it.
Thanks
You can use nodemon in your project to restart your app automatically while your source code directory would be mounted on a volume.
For instance, with this directory structure (which is using Grunt from package.json to run nodemon) :
app/
├── Dockerfile
├── package.json
├── Gruntfile.js
├── src/
│ └── app.js
└── docker-compose.yml
You can use docker-compose which is a tool used to run multiple container. This can be useful if you want to add a database container your app would talk to or any additionnal services interacting with your app.
The following docker-compose config will mount src folder on /usr/src/app/src on the container. With nodemon looking for changes inside src, you will be able to make changes on your machine that will restart the app on the container automatically
To use this you would do :
cd app
docker-compose up
The command above with build the image from dockerfile and start the containers defined in docker-compose.yml.
docker-compose.yml :
version: '2'
services:
your-app:
build: .
ports:
- "8080:8080"
restart: always
container_name: app_container
volumes:
- ./src:/usr/src/app/src
environment:
- SERVER_PORT=8080
Dockerfile :
FROM node:latest
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json .
COPY Gruntfile.js .
RUN npm install
CMD ["npm","start"]
Gruntfile.js :
var path = require('path');
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concurrent: {
dev: {
tasks: ['nodemon'],
options: {
logConcurrentOutput: true
}
}
},
nodemon: {
dev: {
script: 'src/app.js',
options: {
ignore: [
'node_modules/**'
],
ext: 'js'
}
}
},
clean: {}
});
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-nodemon');
grunt.registerTask('default', ['concurrent']);
};
package.json :
{
"name": "your-app",
"version": "1.0.0",
"description": "service",
"scripts": {
"start": "grunt"
},
"author": "someone",
"license": "MIT",
"dependencies": {
"express": "^4.14.0"
},
"devDependencies": {
"grunt": "1.x.x",
"grunt-cli": "1.x.x",
"grunt-concurrent": "2.x.x",
"grunt-nodemon": "0.4.x"
}
}
Sample app.js :
'use strict';
const express = require('express');
const port = process.env.SERVER_PORT;
var app = express();
app.get('/', function(req, res) {
res.send('Hello World');
});
app.listen(port, function() {
console.log('listening on port ' + port);
});
To rebuild the image, you would perform docker-compose build
Each time there is a change and a new image is build, a new <none>:<none> image is created. These images have the same weight as the original one. How can I avoid that ?
You can't. This : iamge is your previous image which was replaced by your new image. So just delete it: docker image prune
Can I use nodemon somehow?
I'm not familiar with that, but it looks like it only restarts your server, but doesnt't do a npm install.
Can I launch this process automatically each time I change something in the code?
I would use Jenkins and automatically build your new Docker image on each git commit.