Home » vue » X-Content-Type-Options blocking CSS with Node on Heroku

X-Content-Type-Options blocking CSS with Node on Heroku

Posted by: admin November 26, 2021 Leave a comment

Questions:

I am trying to deploy a Node.js application to Heroku. The frontend for the application was written in Vue.js. The Vue build output is under /public in the Node app. It works perfectly when launched from localhost and can be accessed as https://localhost:8080/public.

Of course it doesn’t on Heroku. The X-Content-Type-Options header is set by their servers which blocks all CSS and JS files, and I’m getting this error message in Chrome:

Refused to apply style from 'https://my-awesome-app.herokuapp.com/css/app.5364ed87.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

I tinkered a bit with my static files and found what’s wrong. In the production build index.html contains links like this:

<link href=/js/chunk-109f12d9.3bbd3c2d.js rel=prefetch>
<link href=/js/chunk-2d0bae5c.0ec2a734.js rel=prefetch>
<link href=/js/chunk-2d0f1192.aa2d5399.js rel=prefetch>
<link href=/js/chunk-f8fb7b5a.9218edff.js rel=prefetch>
<link href=/css/app.5364ed87.css rel=preload as=style>
<link href=/js/app.af503387.js rel=preload as=script>
<link href=/js/chunk-vendors.aa1329d3.js rel=preload as=script>
<link href=/css/app.5364ed87.css rel=stylesheet>

I found that if I remove the beginning slash from the href attributes, the links suddenly start working. So css/whatever.css works, /css/whatever.css doesn’t.

I suspect that something is wrong with how I enable static directories in my Express setup. But I couldn’t figure out what. Do you have any idea?

const publicPath = path.join(__dirname, 'public');
this.express.use('/public', express.static(publicPath));

Adding a slash anywhere or removing it doesn’t help. I already tried all possible combinations. It doesn’t work as /public, /public/, public/, public, etc.

Could it be that the base URL has to be set in Vue? It’s currently /.

Yes, I know there are plenty of questions about this, but no working answers.

Answers:

You’re receiving this because the server does not respond with css, it’s most likely html, more precisely a 404 page which the browser actually identifies as text/html.

Here are the possible fixes:

  • Check if you’re vue app is actually built with all the js and css files (You might’ve missed the build step for the vue app)

  • Use heroku run bash to inspect your files after they’re built

  • Serve static files with the / url but also don’t let other routes not being reached like so:

    app.get('/api/', ......)
    
    app.use('/public', express.static(path.join(__dirname, 'public')))
    

    Make sure the static setting is the last one.

  • Try visiting the javascript and css urls directly in your broswer to see how the server responds

###

The issue turned out to be not a backend but a frontend one.

Indeed the problem was with the link paths. When Vue generated them, it assumed that the app will be in its own directory’s root, hence all assets will be under /. But they were under /public instead. Therefore when Express tried to serve the static files, index.html was in the right place, but it was trying to find CSS and other assets under /css, and not /public/css. For some reason this didn’t cause a 404 error but a MIME type mismatch instead.

The solution is to change the public path in Vue. Create a vue.config.js file in the project root and add:

module.exports = {
  publicPath: "/public/"
}

Now the asset links will be generated as /public/css and the frontend will work.

Note that ./ doesn’t work because Vue won’t add it but omit the path entirely. The trailing slash isn’t important, Vue will add it if you didn’t.

Here’s a step by step writeup if you like:
https://medium.com/developer-rants/why-is-strict-mime-type-checking-blocking-the-static-serving-of-vue-frontend-files-4cbea1eedbd1