jones
jones

Reputation: 625

Routing problems /w node.js vue app on Azure

I've successfully deployed a node js ap with a Vue frontend on azure but whenever you visit a URL which is not the root, it shows a white screen with the message 'CANNOT GET /products' for example.

In the root of the web server, I have a index.js which will among other things load the content of the dist folder where the compiled vue frontend code is placed: app.use(express.static(__dirname + "/dist"));

I have tried changing my web.config file but if I change <action type="Rewrite" url="index.js"/> to /dist/index.html, my api endpoints stop working and it's basically only a frontend. This is my web config file:

<configuration>
 <system.webServer>
 <webSocket enabled="false" />
 <handlers>
  <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
  <add name="iisnode" path="index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
  <rules>
    <!-- Do not interfere with requests for node-inspector debugging -->
    <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
      <match url="^index.js\/debug[\/]?" />
    </rule>

    <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
    <rule name="StaticContent">
      <action type="Rewrite" url="public{REQUEST_URI}"/>
    </rule>

    <!-- All other URLs are mapped to the node.js site entry point -->
    <rule name="DynamicContent">
      <conditions>
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
      </conditions>
      <action type="Rewrite" url="index.js"/>
    </rule>
  </rules>
</rewrite>
<security>
  <requestFiltering>
    <hiddenSegments>
      <remove segment="bin"/>
    </hiddenSegments>
  </requestFiltering>
 </security>
</system.webServer>
</configuration>

`

Edit - more details on project setup

Folder structure:

Root:

enter image description here

/dist:

enter image description here

Index.js:

const contentRoutes = require("./api/content"); 
const userRoutes = require("./api/users");
const gymRoutes = require("./api/gyms");
...
app.use("/api/content", contentRoutes);
app.use("/api/users", userRoutes);
app.use("/api/gyms", gymRoutes);
...
app.use(express.static(__dirname + "/dist"));

app.listen(port, () => {
  console.log("Server is live");
});

Router.js in Vue project:

Vue.use(Router);

export default new Router({
 routes: [
  {
   path: "/",
   name: "index",
   component: index
   },
  {
   path: "/gyms/new",
   component: gymNew
   },
  {
    path: "/gyms/:id",
    component: gym
   },
   ...
  ],
  mode: "history"

Any idea what I'm doing wrong?

Upvotes: 1

Views: 1713

Answers (2)

Joshua Abbott
Joshua Abbott

Reputation: 442

This is an old post (and requires a lot of config that I no longer find necessary), but is the first thing I came across when researching this problem myself. So I will post my findings here, since this easily solved my problem: https://router.vuejs.org/guide/essentials/history-mode.html#internet-information-services-iis

This gist is to add a web.config as specified to the public folder, which will then be added to the dist folder for production.

Upvotes: 0

Kevin Batongbakal
Kevin Batongbakal

Reputation: 533

const express = require('express')
const serveStatic = require('serve-static')
const app = express()

// First serve static pages from dist folder
var staticPage = serveStatic('dist', {})
app.use(staticPage)

Since it was an SPA, you need to re-route to index.html every time the page refresh or do a new request

// the regex will check if the request url is not /api then redirect to index.html
app.get(/^((?!\/api\/).)*$/, function (req, res) {
    res.sendFile(__dirname + '/dist/index.html')
});

Upvotes: 3

Related Questions