<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have searched the <a href="https://github.com/zeit/next.js/issues?q=is%3Aissue">issues</a> of this repository and believe that this is not a duplicate.</li>
</ul>
<h2 dir="auto">Expected Behavior</h2>


<p dir="auto">I am building a wrapper middleware in express to restrict an entire next application from the public without a password and a username. It should catch every get request that's coming through, check for a logged-in boolean on a session found with an id from a session-cookie.</p>
<h2 dir="auto">Current Behavior</h2>


<p dir="auto">It works as expected for every normal browser http get request, however it does not work for pages served through the <a class="issue-link js-issue-link notranslate" rel="noopener noreferrer nofollow" href="https://linear.app/vercel/issue/NEXT-router">next-router</a>. I noticed this because I had reused a logo component on the restriction page which simply linked to '/' and even though the request went through the middleware and the correct code was run (basic if else with a logged-in boolean) it did serve the homepage.</p>
<h2 dir="auto">Steps to Reproduce (for bugs)</h2>


<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const express = require('express')
const next = require('next')

const app = next({
    dir: '.',
    dev: process.env.NODE_ENV !== 'PRODUCTION'
})

const handle = app.getRequestHandler()
const server = express()

/* HARDCODED VALIDATE BOOLEAN */
const authenticated = false

app.prepare()

.then(() =&gt; {
    /*
        Page restriction middleware
    */
    server.get('*', (req, res) =&gt; {
        console.log(req.path)
        if (!authenticated) {
            console.log('Not authenticated.')
            return app.render(req, res, '/restriction')
        } else {
            console.log('Authenticated.')
            return handle(req, res)
        }

    })

    const PORT = process.env.PORT || process.env.port || 3000
    server.listen(PORT)

})"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-s1">express</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">'express'</span><span class="pl-kos">)</span>
<span class="pl-k">const</span> <span class="pl-s1">next</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">'next'</span><span class="pl-kos">)</span>

<span class="pl-k">const</span> <span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-s1">next</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
    <span class="pl-c1">dir</span>: <span class="pl-s">'.'</span><span class="pl-kos">,</span>
    <span class="pl-c1">dev</span>: <span class="pl-s1">process</span><span class="pl-kos">.</span><span class="pl-c1">env</span><span class="pl-kos">.</span><span class="pl-c1">NODE_ENV</span> <span class="pl-c1">!==</span> <span class="pl-s">'PRODUCTION'</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span>

<span class="pl-k">const</span> <span class="pl-s1">handle</span> <span class="pl-c1">=</span> <span class="pl-s1">app</span><span class="pl-kos">.</span><span class="pl-en">getRequestHandler</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-k">const</span> <span class="pl-s1">server</span> <span class="pl-c1">=</span> <span class="pl-s1">express</span><span class="pl-kos">(</span><span class="pl-kos">)</span>

<span class="pl-c">/* HARDCODED VALIDATE BOOLEAN */</span>
<span class="pl-k">const</span> <span class="pl-s1">authenticated</span> <span class="pl-c1">=</span> <span class="pl-c1">false</span>

<span class="pl-s1">app</span><span class="pl-kos">.</span><span class="pl-en">prepare</span><span class="pl-kos">(</span><span class="pl-kos">)</span>

<span class="pl-kos">.</span><span class="pl-en">then</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c">/*</span>
<span class="pl-c">        Page restriction middleware</span>
<span class="pl-c">    */</span>
    <span class="pl-s1">server</span><span class="pl-kos">.</span><span class="pl-en">get</span><span class="pl-kos">(</span><span class="pl-s">'*'</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-s1">req</span><span class="pl-kos">,</span> <span class="pl-s1">res</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">req</span><span class="pl-kos">.</span><span class="pl-c1">path</span><span class="pl-kos">)</span>
        <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-s1">authenticated</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
            <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'Not authenticated.'</span><span class="pl-kos">)</span>
            <span class="pl-k">return</span> <span class="pl-s1">app</span><span class="pl-kos">.</span><span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-s1">req</span><span class="pl-kos">,</span> <span class="pl-s1">res</span><span class="pl-kos">,</span> <span class="pl-s">'/restriction'</span><span class="pl-kos">)</span>
        <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span>
            <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'Authenticated.'</span><span class="pl-kos">)</span>
            <span class="pl-k">return</span> <span class="pl-s1">handle</span><span class="pl-kos">(</span><span class="pl-s1">req</span><span class="pl-kos">,</span> <span class="pl-s1">res</span><span class="pl-kos">)</span>
        <span class="pl-kos">}</span>

    <span class="pl-kos">}</span><span class="pl-kos">)</span>

    <span class="pl-k">const</span> <span class="pl-c1">PORT</span> <span class="pl-c1">=</span> <span class="pl-s1">process</span><span class="pl-kos">.</span><span class="pl-c1">env</span><span class="pl-kos">.</span><span class="pl-c1">PORT</span> <span class="pl-c1">||</span> <span class="pl-s1">process</span><span class="pl-kos">.</span><span class="pl-c1">env</span><span class="pl-kos">.</span><span class="pl-c1">port</span> <span class="pl-c1">||</span> <span class="pl-c1">3000</span>
    <span class="pl-s1">server</span><span class="pl-kos">.</span><span class="pl-en">listen</span><span class="pl-kos">(</span><span class="pl-c1">PORT</span><span class="pl-kos">)</span>

<span class="pl-kos">}</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">This code should never log 'Authenticated' much less actually serve the requested resource right?<br>
Here's the thing, it never logs 'Authenticated' but it does serve any page you want if it was requested with next/link.</p>
<p dir="auto">Front-end to reproduce:</p>
<p dir="auto">index.js</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export default () =&gt;
  &lt;div&gt;Restricted page. You cant see this without bypassing the express routing middleware.&lt;/div&gt;"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span>
  <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>Restricted page. You cant see this without bypassing the express routing middleware.<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span></pre></div>
<p dir="auto">restriction.js</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import Link from 'next/link'
export default () =&gt;
    &lt;Link href=&quot;/&quot;&gt;&lt;button&gt;I am the magic resctriction bypasser.&lt;/button&gt;&lt;/Link&gt;"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-v">Link</span> <span class="pl-k">from</span> <span class="pl-s">'next/link'</span>
<span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span>
    <span class="pl-c1">&lt;</span><span class="pl-ent">Link</span> <span class="pl-c1">href</span><span class="pl-c1">=</span><span class="pl-s">"/"</span><span class="pl-c1">&gt;</span><span class="pl-c1">&lt;</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span>I am the magic resctriction bypasser.<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span><span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">Link</span><span class="pl-c1">&gt;</span></pre></div>
<p dir="auto">What's sort of funny about this is that you can click on that Link in the restriction page and then refresh the page and the middleware will render the restriction page again.</p>
<p dir="auto">When using <code class="notranslate">docker build .</code> on our production server, I get the following error:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="...
Step 12/14 : RUN yarn build
 ---&gt; Running in 95abf61028ab
yarn run v1.3.2
$ next build
&gt; Using external babel configuration
&gt; Location: &quot;/usr/src/app/.babelrc&quot;
&gt; Using external babel configuration
&gt; Location: &quot;/usr/src/app/.babelrc&quot;
&gt; Using external babel configuration
&gt; Location: &quot;/usr/src/app/.babelrc&quot;
&gt; Using external babel configuration
&gt; Location: &quot;/usr/src/app/.babelrc&quot;
&gt; Failed to build
{ Error: (client) ./app/src/styles/pages/marketing.scss
Module build failed: ModuleBuildError: Module build failed: 
#react-nav-root {
      ^
      Invalid CSS after &quot;    if&quot;: expected &quot;{&quot;, was &quot;(module.hot) {&quot;
..."><pre class="notranslate"><code class="notranslate">...
Step 12/14 : RUN yarn build
 ---&gt; Running in 95abf61028ab
yarn run v1.3.2
$ next build
&gt; Using external babel configuration
&gt; Location: "/usr/src/app/.babelrc"
&gt; Using external babel configuration
&gt; Location: "/usr/src/app/.babelrc"
&gt; Using external babel configuration
&gt; Location: "/usr/src/app/.babelrc"
&gt; Using external babel configuration
&gt; Location: "/usr/src/app/.babelrc"
&gt; Failed to build
{ Error: (client) ./app/src/styles/pages/marketing.scss
Module build failed: ModuleBuildError: Module build failed: 
#react-nav-root {
      ^
      Invalid CSS after "    if": expected "{", was "(module.hot) {"
...
</code></pre></div>
<p dir="auto">Above, <code class="notranslate">yarn build</code> points to <code class="notranslate">next build</code>.</p>
<p dir="auto">When docker is building the image, it generates the node_modules dir from scratch (dir is not present when pulling from github repo).</p>
<p dir="auto">Notice how "Using external babel configuration" is repeated four times, and that there is no mention of using a webpack config. I use a css/scss loader in my next.config.js, and it looks like that file is not getting loaded, which is why it can't parse this scss file. A successful build locally (using <code class="notranslate">docker build .</code> with node_modules dir present) looks like this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="...
Step 12/14 : RUN yarn build
 ---&gt; Running in b1d43e9221e8
yarn run v1.3.2
$ next build
&gt; Using external babel configuration
&gt; Location: &quot;/usr/src/app/.babelrc&quot;
&gt; Using &quot;webpack&quot; config function defined in next.config.js.
Done in 77.93s.
..."><pre class="notranslate"><code class="notranslate">...
Step 12/14 : RUN yarn build
 ---&gt; Running in b1d43e9221e8
yarn run v1.3.2
$ next build
&gt; Using external babel configuration
&gt; Location: "/usr/src/app/.babelrc"
&gt; Using "webpack" config function defined in next.config.js.
Done in 77.93s.
...
</code></pre></div>
<p dir="auto">Notice that it finds the webpack config no problem.</p>
<p dir="auto">Here is my Dockerfile (some parts redacted):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="FROM mhart/alpine-node:9.3.0

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN yarn install

# Bundle app source
COPY . /usr/src/app

# build
RUN yarn build
EXPOSE 3000

CMD [ &quot;yarn&quot;, &quot;serve&quot; ]"><pre class="notranslate"><code class="notranslate">FROM mhart/alpine-node:9.3.0

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN yarn install

# Bundle app source
COPY . /usr/src/app

# build
RUN yarn build
EXPOSE 3000

CMD [ "yarn", "serve" ]
</code></pre></div>
<p dir="auto">I believe the problem is due to <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="266124614" data-permission-text="Title is private" data-url="https://github.com/vercel/next.js/issues/3119" data-hovercard-type="pull_request" data-hovercard-url="/vercel/next.js/pull/3119/hovercard" href="https://github.com/vercel/next.js/pull/3119">#3119</a>. Rolling back to next@4.2.0 solved the problem.</p>
<p dir="auto"><a href="https://github.com/jasonbarry/next.js/tree/canary-fix-dist">My fork</a>, which is a copy of next@4.3.0-canary.1 with <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="266124614" data-permission-text="Title is private" data-url="https://github.com/vercel/next.js/issues/3119" data-hovercard-type="pull_request" data-hovercard-url="/vercel/next.js/pull/3119/hovercard" href="https://github.com/vercel/next.js/pull/3119">#3119</a> rolled back, also fixes the problem.</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have searched the <a href="https://github.com/zeit/next.js/issues">issues</a> of this repository and believe that this is not a duplicate.</li>
</ul>
<h2 dir="auto">Context</h2>
<p dir="auto">Building with <code class="notranslate">next build</code> works when I am developing locally and have my node_modules dir present. However, our production servers use docker to build our image. In my project, node_modules aren't checked in, they get recreated via yarn. Next is unable to locate it after <code class="notranslate">yarn install</code>, or does something very fishy. This has something to do with <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="266124614" data-permission-text="Title is private" data-url="https://github.com/vercel/next.js/issues/3119" data-hovercard-type="pull_request" data-hovercard-url="/vercel/next.js/pull/3119/hovercard" href="https://github.com/vercel/next.js/pull/3119">#3119</a> because reverting that change fixed the problem for me.</p>
<p dir="auto">This is preventing us from deploying our app with the latest canary release.</p>
<h2 dir="auto">Your Environment</h2>
<table role="table">
<thead>
<tr>
<th>Tech</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>next</td>
<td>4.3.0-canary.1</td>
</tr>
<tr>
<td>node</td>
<td>8.9.1</td>
</tr>
<tr>
<td>OS</td>
<td>10.12.6</td>
</tr>
</tbody>
</table>