have created an Asp.NET Core Web Application with Angular 9. I have added Angular Universal to my application. Now I need to publish my application into the Azure app service.
I have used the following command to build an application,
npm run build:ssr
After building angular universal application it will give two folder structures under the dist folder.
dist/{app-name}/browser
dist/{app-name}/server
It's working fine locally. Now I need to publish the application in the Azure app service. So far I have searched a lot of things and integrated them. But unfortunately, I did not find any solution to work for the last couple of days.
Here is my web.config file
<?xml version="1.0" encoding="utf-8"?>
<configuration>`
<system.webServer>
<webSocket enabled="false"/>
<handlers>
<add name="iisnode" path="index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^/index.js\/debug[\/]?"/>
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="index.js"/>
</rule>
<rule name="DigitalTalksAngulartest" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/digitaltalkstest/" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
</configuration>
server.ts file
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
let distFolder = join(process.cwd(),'dist/#abb/customer-platform/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
const win = mock.getWindow();
global['window'] = win;
global['document'] = mock.getDocument();
global['location'] = mock.getLocation();
global['navigator'] = mock.getNavigator();
global['history'] = mock.getHistory();
global['localStorage'] = mock.getLocalStorage();
global['sessionStorage'] = mock.getSessionStorage();
global['object'] = win.object;
global['HTMLElement'] = win.HTMLElement;
global['Event'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global.Buffer = global.Buffer || require('buffer').Buffer;
global.btoa = function (str) {
return Buffer.from(str, 'binary').toString('base64');
};
global.atob = function (b64Encoded) {
return Buffer.from(b64Encoded, 'base64').toString('binary');
};
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
currently, the normal angular application resides in site/wwwroot/projec-name
Inside this path, all my build contents reside. Build content consists of web.config, index.html, and all other files.
Any help is appreciated.
Related
Looking for some assistance with this error.
After hosting my Node.js & Angular project at azure I'm getting that error on POST request:
Http failure response for https://https://green-market.azurewebsites.net/api/auth/login: 405 Method Not Allowed
This is my web.config file:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="iisnode" />
<add name="iisnode" path="app.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="Angular Routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile"
negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"
negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
<staticContent>
<mimeMap fileExtension="woff" mimeType="application/font-woff" />
<mimeMap fileExtension="json" mimeType="application/json" />
</staticContent>
</system.webServer>
</configuration>
And this is my app.js file from node.js server:
let originUrl;
if (process.env.PORT) {
global.config = require("./config-prod");
originUrl = "https://green-market.azurewebsites.net";
}
else {
global.config = require("./config-dev");
originUrl = "http://localhost:4200";
}
require("./data-access-layer/dal");
const express = require("express");
const session = require("express-session");
const path = require("path");
const cors = require("cors");
const productsController = require("./controllers/products-controller");
const authController = require("./controllers/auth-controller");
const shoppingCartsController = require("./controllers/shopping-carts-controller");
const ordersController = require("./controllers/orders-controller");
const citiesController = require("./controllers/cities-controller");
const server = express();
const fileUpload = require("express-fileupload");
const { request, response } = require("express");
const { url } = require("inspector");
server.use(fileUpload());
server.use(express.json());
server.use(express.static(path.join(__dirname, "./_front-end")));
server.use(cors({
origin: originUrl,
credentials: true
}));
server.use(session({
name: "OnlineMarketSession",
secret: "itsASecret",
resave: true,
saveUninitialized: false,
}));
server.use("/api/products", productsController);
server.use("/api/shopping-carts", shoppingCartsController);
server.use("/api/orders", ordersController);
server.use("/api/auth", authController);
server.use("/api/cities", citiesController);
// Any other route - return index.html as we are SPA:
server.use("*", (request, response) => {
response.sendFile(path.join(__dirname, "./_front-end/index.html"));
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log(`Listening on port ${port}`));
Thank you!
I'm trying to host a simple Nextjs application on Azure WebApp, i have tried to follow several online tutorials to configure it but none managed to help me.
I'm using the SSR configuration of the Nextjs and have only created two components to test it on the Azure hosting.
Right now i'm stuck at the server configuration for Node, i have tried place a web.config file that i saw on an example but it seems that my request isn't event reaching the application server.
This is my web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="app/server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="API">
<match url="^api(.*)$" />
<conditions logicalGrouping="MatchAll">
<add input="{SCRIPT_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{SCRIPT_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="api/index.php" appendQueryString="true" />
</rule>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^app/server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="app/server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
This is my server.js
const express = require('express')
const next = require('next')
const nextConfig = require('../next.config')
const port = process.env.PORT || 8080
const dev = process.env.NODE_ENV !== 'production'
const app = next({
dev: dev,
dir: './app',
conf: nextConfig
})
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.get('/home', (req, res) => {
return app.render(req, res, '/home', req.query)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
I'm developping a nodeJS/Angular 6/Express app.
There's only 1 route in express for the "back-end" and many routes for angular.
I have no problems to run that locally but when I try to deploy it on Azure, Angular routes works fine but not back-end routes (which redirect me to the root url).
I think Angular is taking priority on back-end routes.
Here are some files :
server.js :
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const fetch = require('node-fetch');
const publicweb = './dist/forms';
const app = express();
app.use(express.static(publicweb));
app.use('/api/test', (req, res) => {
res.send("test");
});
app.get('*', (req, res) => {
res.sendFile('index.html', { root: publicweb });
});
const port = '1337';
app.listen(port, () => console.log(`API running on localhost:${port}`));
web.config :
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="Express.js URIs">
<match url="api/*" />
<action type="Rewrite" url="server.js" />
</rule>
<rule name="Angular" stopProcessing="true">
<match url="/*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"
negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
package.json :
"start" : "node src/server.js"
app-routing.module.ts :
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { RetailComponent } from './retail/form/retail.component';
const routes: Routes = [
{
path: '',
redirectTo: '/',
pathMatch: 'full'
},
{
path: 'retail',
component: RetailComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
When I deploy that app on Azure, and I try to access /api/test
My build definition in Azure
Many thanks for your answer!
I think all your get request are mapping to this piece of code
app.get('*', (req, res) => {
enter code here`res.sendFile('index.html', { root: publicweb });
});
that is why you are getting index.html in your queries to your server.
And app.use() is to be used for applying middleware so after middleware work is over the app.get() method gets executed and so you get index.html
I have constructed a website using a react/webpack dev-server. I want to deploy the site to the web server now. I have cloned the project from github to the server. I have created a new website and app pool in iis and set the basic path to the website folder where my index.html file is. I run the npm start command which concurrently launches the dev server (port 8081) and the node.js server (port 5000) .... I can see the dev server with no issue when I go to localhost:8081 but when I go to localhost:8080 the page times out and displays a
Bad Request - Invalid Hostname
HTTP Error 400. The request hostname is invalid.
error message. Can someone tell me whats wrong with my web.config file and why IIS won't proxy the node server and dist folder? (I am using url rewrite)
Here is my webpack.config (located in root folder):
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://localhost:8081',
'webpack/hot/only-dev-server',
'./src/index.js'
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff2?|ttf|svg|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
}
],
},
devServer: {
historyApiFallback: true,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
]
};
Here is the server.js (located in /server/core/ folder):
const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
const config = require('../../webpack.config.js');
const options = {
contentBase: './dist',
hot: true
};
var app = require('express')();
var cors = require('cors');
var bodyParser = require('body-parser')
webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);
app.listen(process.env.PORT || 5000, () => {
console.log('dev server listening on port 5000');
});
and finally here is the web.config file (located in the root folder):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="/\server/\core/\server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="/\server/\core/\server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
Finally Here is my folder structure:
I want to run angular 4 univeral in Azure Web. I deployed the code, but I have some troubles with web.config (i think so).
The server.js located in dist folder, so I set path in web.config "dist/server.js", but when server.js runs it gives an error:
ENOENT: no such file or directory, open 'D:\home\site\wwwroot\dist\dist\browser\index.html'
If I remove the "dist" from path it will 404. And if I remove "dist" from
const DIST_FOLDER = join(process.cwd(), 'dist'); in server.js
it will give me an error:
ENOENT: no such file or directory, open 'D:\home\site\wwwroot\browser\index.html'
Or double dist, or no dist at all.
The web.config looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="dist/server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^dist/server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="dist/server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
The server.js code:
const PORT = process.env.PORT || 8080;
const DIST_FOLDER = join(process.cwd(), 'dist');
const app = express();
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
const { AppServerModuleNgFactory } = require('main.server');
app.engine('html', (_, options, callback) => {
const opts = { document: template, url: options.req.url };
renderModuleFactory(AppServerModuleNgFactory, opts)
.then(html => callback(null, html));
});
app.set('view engine', 'html');
app.set('views', 'src');
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
app.get('*', (req, res) => {
res.render('index', { req });
});
app.listen(PORT, () => {
console.log(`listening on http://localhost:${PORT}!`);
});
I figured out, instead of process.cwd(), I should use __dirname.
Your server.js is located in "dist" folder. So, please change the following line
const DIST_FOLDER = join(process.cwd(), 'dist');
to
const DIST_FOLDER = process.cwd();