Nextjs, React & Mysql

Good day,
I’m having issue with running my react + mysql in docker.
It just returns me this when running docker-compose up -d

2023-09-08 16:01:47 /app/node_modules/next/dist/compiled/undici/index.js:1
2023-09-08T08:01:47.836970989Z (()=>{var __webpack_modules__={1900:(A,e,t)=>{"use strict";const{parseContentType:s}=t(4318);function getInstance(A){const e=A.headers;const t=s(e["content-type"]);if(!t)throw new Error("Malformed content type");for(const s of o){const o=s.detect(t);if(!o)continue;const r={limits:A.limits,headers:e,conType:t,highWaterMark:undefined,fileHwm:undefined,defCharset:undefined,defParamCharset:undefined,preservePath:false};if(A.highWaterMark)r.highWaterMark=A.highWaterMark;if(A.fileHwm)r.fileHwm=A.fileHwm;r.defCharset=A.defCharset;r.defParamCharset=A.defParamCharset;r.preservePath=A.preservePath;return new s(r)}throw new Error(`Unsupported content type: ${e["content-type"]}`)}const o=[t(6104),t(8506)].filter((function(A){return typeof A.detect==="function"}));A.exports=A=>{if(typeof A!=="object"||A===null)A={};if(typeof A.headers!=="object"||A.headers===null||typeof A.headers["content-type"]!=="string"){throw new Error("Missing Content-Type")}return getInstance(A)}},6104:(A,e,t)=>{"use strict";const{Readable:s,Writable:o}=t(2781);const r=t(6542);const{basename:i,convertToUTF8:n,getDecoder:g,parseContentType:C,parseDisposition:E}=t(4318);const Q=Buffer.from("\r\n");const I=Buffer.from("\r");const B=Buffer.from("-");function noop(){}const a=2e3;const c=16*1024;const h=0;const l=1;const u=2;class HeaderParser{constructor(A){this.header=Object.create(null);this.pairCount=0;this.byteCount=0;this.state=h;this.name="";this.value="";this.crlf=0;this.cb=A}reset(){this.header=Object.create(null);this.pairCount=0;this.byteCount=0;this.state=h;this.name="";this.value="";this.crlf=0}push(A,e,t){let s=e;while(e<t){switch(this.state){case h:{let o=false;for(;e<t;++e){if(this.byteCount===c)return-1;++this.byteCount;const t=A[e];if(f[t]!==1){if(t!==58)return-1;this.name+=A.latin1Slice(s,e);if(this.name.length===0)return-1;++e;o=true;this.state=l;break}}if(!o){this.name+=A.latin1Slice(s,e);break}}case l:{let o=false;for(;e<t;++e){if(this.byteCount===c)return-1;++this.byteCount;const t=A[e];if(t!==32&&t!==9){s=e;o=true;this.state=u;break}}if(!o)break}case u:switch(this.crlf){case 0:for(;e<t;++e){if(this.byteCount===c)return-1;++this.byteCount;const t=A[e];if(y[t]!==1){if(t!==13)return-1;++this.crlf;break}}this.value+=A.latin1Slice(s,e++);break;case 1:if(this.byteCount===c)return-1;++this.byteCount;if(A[e++]!==10)return-1;++this.crlf;break;case 2:{if(this.byteCount===c)return-1;++this.byteCount;const t=A[e];if(t===32||t===9){s=e;this.crlf=0}else{if(++this.pairCount<a){this.name=this.name.toLowerCase();if(this.header[this.name]===undefined)this.header[this.name]=[this.value];else this.header[this.name].push(this.value)}if(t===13){++this.crlf;++e}else{s=e;this.crlf=0;this.state=h;this.name="";this.value=""}}break}case 3:{if(this.byteCount===c)return-1;++this.byteCount;if(A[e++]!==10)return-1;const t=this.header;this.reset();this.cb(t);return e}}break}}return e}}class FileStream extends s{constructor(A,e){super(A);this.truncated=false;this._readcb=null;this.once("end",(()=>{this._read();if(--e._fileEndsLeft===0&&e._finalcb){const A=e._finalcb;e._finalcb=null;process.nextTick(A)}}))}_read(A){const e=this._readcb;if(e){this._readcb=null;e()}}}const d={push:(A,e)=>{},destroy:()=>{}};function callAndUnsetCb(A,e){const t=A._writecb;A._writecb=null;if(e)A.destroy(e);else if(t)t()}function nullDecoder(A,e){return A}class Multipart extends o{constructor(A){const e={autoDestroy:true,emitClose:true,highWaterMark:typeof A.highWaterMark==="number"?A.highWaterMark:undefined};super(e);if(!A.conType.params||typeof A.conType.params.boundary!=="string")throw new Error("Multipart: Boundary not found");const t=A.conType.params.boundary;const s=typeof A.defParamCharset==="string"&&A.defParamCharset?g(A.defParamCharset):nullDecoder;const o=A.defCharset||"utf8";const a=A.preservePath;const c={autoDestroy:true,emitClose:true,highWaterMark:typeof A.fileHwm==="number"?A.fileHwm:undefined};const h=A.limits;const l=h&&typeof h.fieldSize==="number"?h.fieldSize:1*1024*1024;const u=h&&typeof h.fileSize==="number"?h.fileSize:Infinity;const f=h&&typeof h.files==="number"?h.files:Infinity;const y=h&&typeof h.fields==="number"?h.fields:Infinity;const D=h&&typeof h.parts==="number"?h.parts:Infinity;let k=-1;let w=0;let S=0;let p=false;this._fileEndsLeft=0;this._fileStream=undefined;this._complete=false;let N=0;let R;let b=0;let m;let F;let L;let M;let U=false;let Y=false;let J=false;this._hparser=null;const q=new HeaderParser((A=>{this._hparser=null;p=false;L="text/plain";m=o;F="7bit";M=undefined;U=false;let e;if(!A["content-disposition"]){p=true;return}const t=E(A["content-disposition"][0],s);if(!t||t.type!=="form-data"){p=true;return}if(t.params){if(t.params.name)M=t.params.name;if(t.params["filename*"])e=t.params["filename*"];else if(t.params.filename)e=t.params.filename;if(e!==undefined&&!a)e=i(e)}if(A["content-type"]){const e=C(A["content-type"][0]);if(e){L=`${e.type}/${e.subtype}`;if(e.params&&typeof e.params.charset==="string")m=e.params.charset.toLowerCase()}}if(A["content-transfer-encoding"])F=A["content-transfer-encoding"][0].toLowerCase();if(L==="application/octet-stream"||e!==undefined){if(S===f){if(!Y){Y=true;this.emit("filesLimit")}p=true;return}++S;if(this.listenerCount("file")===0){p=true;return}N=0;this._fileStream=new FileStream(c,this);++this._fileEndsLeft;this.emit("file",M,this._fileStream,{filename:e,encoding:F,mimeType:L})}else{if(w===y){if(!J){J=true;this.emit("fieldsLimit")}p=true;return}++w;if(this.listenerCount("field")===0){p=true;return}R=[];b=0}}));let T=0;const ssCb=(A,e,t,s,o)=>{A:while(e){if(this._hparser!==null){const A=this._hparser.push(e,t,s);if(A===-1){this._hparser=null;q.reset();this.emit("error",new Error("Malformed part header"));break}t=A}if(t===s)break;if(T!==0){if(T===1){switch(e[t]){case 45:T=2;++t;break;case 13:T=3;++t;break;default:T=0}if(t===s)return}if(T===2){T=0;if(e[t]===45){this._complete=true;this._bparser=d;return}const A=this._writecb;this._writecb=noop;ssCb(false,B,0,1,false);this._writecb=A}else if(T===3){T=0;if(e[t]===10){++t;if(k>=D)break;this._hparser=q;if(t===s)break;continue A}else{const A=this._writecb;this._writecb=noop;ssCb(false,I,0,1,false);this._writecb=A}}}if(!p){if(this._fileStream){let A;const r=Math.min(s-t,u-N);if(!o){A=Buffer.allocUnsafe(r);e.copy(A,0,t,t+r)}else{A=e.slice(t,t+r)}N+=A.length;if(N===u){if(A.length>0)this._fileStream.push(A);this._fileStream.emit("limit");this._fileStream.truncated=true;p=true}else if(!this._fileStream.push(A)){if(this._writecb)this._fileStream._readcb=this._writecb;this._writecb=null}}else if(R!==undefined){let A;const r=Math.min(s-t,l-b);if(!o){A=Buffer.allocUnsafe(r);e.copy(A,0,t,t+r)}else{A=e.slice(t,t+r)}b+=r;R.push(A);if(b===l){p=true;U=true}}}break}if(A){T=1;if(this._fileStream){this._fileStream.push(null);this._fileStream=null}else if(R!==undefined){let A;switch(R.length){case 0:A="";break;case 1:A=n(R[0],m,0);break;default:A=n(Buffer.concat(R,b),m,0)}R=undefined;b=0;this.emit("field",M,A,{nameTruncated:false,valueTruncated:U,encoding:F,mimeType:L})}if(++k===D)this.emit("partsLimit")}};this._bparser=new r(`\r\n--${t}`,ssCb);this._writecb=null;this._finalcb=null;this.write(Q)}static detect(A){return A.type==="multipart"&&A.subtype==="form-data"}_write(A,e,t){this._writecb=t;this._bparser.push(A,0);if(this._writecb)callAndUnsetCb(this)}_destroy(A,e){this._hparser=null;this._bparser=d;if(!A)A=checkEndState(this);const t=this._fileStream;if(t){this._fileStream=null;t.destroy(A)}e(A)}_final(A){this._bparser.destroy();if(!this._complete)return A(new Error("Unexpected end of form"));if(this._fileEndsLeft)this._finalcb=finalcb.bind(null,this,A);else finalcb(this,A)}}function finalcb(A,e,t){if(t)return e(t);t=checkEndState(A);e(t)}function checkEndState(A){if(A._hparser)return new Error("Malformed part header");const e=A._fileStream;if(e){A._fileStream=null;e.destroy(new Error("Unexpected end of file"))}if(!A._complete)return new Error("Unexpected end of form")}const f=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];const y=[0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1];A.exports=Multipart},8506:(A,e,t)=>{"use strict";const{Writable:s}=t(2781);const{getDecoder:o}=t(4318);class URLEncoded extends s{constructor(A){const e={autoDestroy:true,emitClose:true,highWaterMark:typeof A.highWaterMark==="number"?A.highWaterMark:undefined};super(e);let t=A.defCharset||"utf8";if(A.conType.params&&typeof A.conType.params.charset==="string")t=A.conType.params.charset;this.charset=t;const s=A.limits;this.fieldSizeLimit=s&&typeof s.fieldSize==="number"?s.fieldSize:1*1024*1024;this.fieldsLimit=s&&typeof s.fields==="number"?s.fields:Infinity;this.fieldNameSizeLimit=s&&typeof s.fieldNameSize==="number"?s.fieldNameSize:100;this._inKey=true;this._keyTrunc=false;this._valTrunc=false;this._bytesKey=0;this._bytesVal=0;this._fields=0;this._key="";this._val="";this._byte=-2;this._lastPos=0;this._encode=0;this._decoder=o(t)}static detect(A){return A.type==="application"&&A.subtype==="x-www-form-urlencoded"}_write(A,e,t){if(this._fields>=this.fieldsLimit)return t();let s=0;const o=A.length;this._lastPos=0;if(this._byte!==-2){s=readPctEnc(this,A,s,o);if(s===-1)return t(new Error("Malformed urlencoded form"));if(s>=o)return t();if(this._inKey)++this._bytesKey;else++this._bytesVal}A:while(s<o){if(this._inKey){s=skipKeyBytes(this,A,s,o);while(s<o){switch(A[s]){case 61:if(this._lastPos<s)this._key+=A.latin1Slice(this._lastPos,s);this._lastPos=++s;this._key=this._decoder(this._key,this._encode);this._encode=0;this._inKey=false;continue A;case 38:if(this._lastPos<s)this._key+=A.latin1Slice(this._lastPos,s);this._lastPos=++s;this._key=this._decoder(this._key,this._encode);this._encode=0;if(this._bytesKey>0){this.emit("field",this._key,""...

Dockerfile

FROM node:14
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . ./
CMD ["npm", "start"]

docker-compose.yml

version: '3.8'
services:
  nextjs:
    build:
      context: .
    volumes:
      - .:/var/www/html
    ports:
      - "4000:4000"
    depends_on:
      - nextmysql
    stdin_open: true
    command: next start

  nextmysql:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nextdb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"

  nextphpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - '4080:80'
    environment:
      TZ: Asia/Manila
      PMA_HOST: nextmysql
    depends_on:
      - nextmysql

For security reasons, you should use node >= 18.

The end-of-life date for Node.js 14 is April 30, 2023.

It seems strange that you first copy package, then install with npm, then copy EVERYTHING from your local folder into the image. That would potentially overwrite your fresh installed node_modules, maybe there is a mismatch.

My first approach would be to go into the container (docker exec -it <cid> sh), look at the files, try to start manually. If the container exists immediately, I would try to run an endless loop at the end of the Dockerfile.

Are you sure you need stdin_open: true?

1 Like

I’ve manage to fix but new error occured:

node:internal/modules/cjs/loader:1051
  throw err;
  ^

Error: Cannot find module '/app/next'
    at Module._resolveFilename (node:internal/modules/cjs/loader:1048:15)
    at Module._load (node:internal/modules/cjs/loader:901:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at node:internal/main/run_main_module:23:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

Node.js v20.6.0

This is the mounted files:

My Dockerfile:

version: '3.8'
services:
  nextjs:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/app
    ports:
      - "4000:4000"
    depends_on:
      - nextmysql
    command: next start

  nextmysql:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nextdb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"

  nextphpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - '4080:80'
    environment:
      TZ: Asia/Manila
      PMA_HOST: nextmysql
    depends_on:
      - nextmysql

That’s not your Dockerfile, it’s your docker-compose.yml file :wink:

Sorry, typo error correct that’s my docker-compose.yml file
But this returns an error:

node:internal/modules/cjs/loader:1051
  throw err;
  ^

Error: Cannot find module '/app/next'
    at Module._resolveFilename (node:internal/modules/cjs/loader:1048:15)
    at Module._load (node:internal/modules/cjs/loader:901:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at node:internal/main/run_main_module:23:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

Node.js v20.6.0

This is my Dockerfile:

FROM node:latest

WORKDIR /app

COPY . .

RUN npm cache clean --force
RUN npm install
RUN NODE_ENV=production npm run build

EXPOSE 4000

CMD ["npm", "start"]

Go into the container and check what’s going on. Can you execute it manually? Is a /app/next folder present? What is the npm start command in package.json?

When you have a build process, nowadays you would use a multi-stage build process. You don’t need all the build tools and sources in your production image.

1 Like

It could seem strange, but that is indeed a common practice. That way if package.json or the lock file changes, those layers will be invalidated and npm install can run again, but if the json files don’t change, only the app sourcecode, you don’t need to rebuild the dependencies. So even though the json files will be copied twice, it will generate a smaller image,

By the way, @dyey this seems strange in your folder stucture too (on the screenshot):

/app/app/

You probably copied your whole project root into /app in the container, including the “app” folder in your project root. If the module named “next” is in that folder, that explains why it can’t be found.

If that’s not the case, please, explain why you expect “/app/next” to exist. Issues are usually programming issues until you can find out what is copied to a wrong place where it was not expected to be. So exactly as @bluepuma77 wrote:

Since you can also browse the files as you have already done it, you just have to find the files, When you know what is wrong with the files, you can ask for help what you did wrong in your Dockerfile or compose file.

1 Like

Now it’s running

But the port in logs is 3000 not 2000(set in my Dockerfile)

2023-09-11 10:44:28 - warn "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
2023-09-11 10:44:28 - warn "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
2023-09-11 10:44:28 
2023-09-11 10:44:28 > next-mysql@0.1.0 start
2023-09-11 10:44:28 > next start
2023-09-11 10:44:28 
2023-09-11 10:44:28 - ready started server on [::]:3000, url: http://localhost:3000
2023-09-11 10:44:28 - info Loaded env from /app/.env
2023-09-11 10:44:28 - info Loaded env from /app/.env

@rimelek I am still not convinced that this a good approach.

If you run a different OS or a different NodeJS version, the node_modules folder from host may contain different things than node_modules from container. Some packages even compile some code.

And I would expect that this is just overwriting node_modules in container with the host version, even though it has already created its own version inside the container.

1 Like

The first screenshot of the folder on the host (The second screenshot of the files was created from Docker Desktop) shows a .dockerignore. That file must contain node_modules so it can be ignored. Without that, you are right, node_modules in the container could be overwritten.

1 Like

On second thought, there is a bind mount in the compose file, so node_modules is indeed overwritten. Hm… that could very easily be the reason of the error too.

Edit:

Could have been… I missed the message about the running services.

You have to forward the right port from the host to the container. EXPOSE in the dockerfile does nothing. It is just metadata. How would the service in the container know that it has to listen on another port? :slight_smile:

In the compose file in the ports section the left side must be the port on the host and the second is the port in the container.