Routes on a deployed Angular app do not work when served by Node with Express. I know this has been asked before but there is something I am probably missing that is driving me crazy.
File structure in the "express" folder where Node runs is roughly the following:
express
├── controller.js
├── index.js
├── ngForm
│ ...see below...
├── node_modules
│ ...
├── package.json
├── public
│ ├── file.json
│ └── rubric.html
├── router.js
├── ssl
├── cert.pem
└── key.pem
and the Angular project is in ngForm:
ngForm
├── angular.json
├── dist
│ └── rubric
│ ├── assets
│ ├── favicon.ico
│ ├── index.html
│ ├── main.js
│ ├── main.js.map
│ ├── polyfills.js
│ ├── polyfills.js.map
│ ├── runtime.js
│ ├── runtime.js.map
│ ├── styles.js
│ ├── styles.js.map
│ ├── vendor.js
│ └── vendor.js.map
├── e2e
├── node_modules
├── package.json
├── src
├── tsconfig.json
└── tslint.json
Some relevant Angular code:
app.module.ts:
const appRoutes: Routes = [
{path: '', redirectTo: '/rubric', pathMatch: 'full' },
{path: 'rubric', component: RubricComponent},
{path: 'rubricbuilder', component: RubricbuilderComponent},
{path: '**', component: PageNotFoundComponent}
]
app.component.ts:
#Component({
selector: 'app-root',
styleUrls: ['app.component.scss'],
template: `<router-outlet></router-outlet>`
})
The relevant Node.js code:
server.js:
app.use(express.static("ngForm/dist/rubric"));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'ngForm/dist/rubric/index.html'));
});
I did run ng build from the Angular project in ngForm, and the output is in ngForm/dist.
When running ng serve in the AngularProject I can navigate to
https://localhost:4200/rubric and https://localhost:4200/rubricbuilder .
From Node I can only get to https://localhost:8000/ which redirects/changes the url to https://localhost:8000/rubric , but I cannot launch https://localhost:8000/rubric itself or https://localhost:8000/rubricbuilder. By poking around with the angular routes and re-running the build, I can make express show rubricbuilder on the / route, which changes the url to https://localhost:8000/rubricbuilder. What am I missing?
I'm not that familiar with angular but this question is related to VueRouter.
Because you did not define /rubric router in express middleware so you might get an error like 404 NOT FOUND.
When using SPA router in HTML5 history mode, you need extra configurations for your server,
for example, send your SPA at every route:
app.use(express.static("ngForm/dist/rubric"));
app.use((req, res) => {
res.sendFile(path.join(__dirname, 'ngForm/dist/rubric/index.html'));
});
This might not be the best practice for express, you can search for other solutions, for example like VueRouter suggest using connect-history-api-fallback with express.
Related
I have a project with the following (very schematic) file structure:
.
├── backend
│ ├── config
│ ├── controllers
│ ├── middleware
│ ├── models
│ ├── routes
│ └── server.js
├── frontend
│ ├── node_modules
│ ├── package.json <== Eslint + Prettier here
│ ├── postcss.config.js
│ ├── public
│ ├── src
│ ├── tailwind.config.js
│ └── yarn.lock
├── node_modules
├── package.json <== Eslint + Prettier here
└── yarn.lock
The backend is an express server, the frontend a React app.
I want to have my eslint and prettier configs in both package.json files (different rules apply, indicated in the tree above) but if I cannot compile because they conflict.
I added these to both package.json files:
"eslintConfig": {
"extends": "#gbrachetta/eslint-config",
"rules": {
"sort-imports": "off",
"import/order": "off"
}
},
"prettier": "#gbrachetta/prettier-config"
but as mentioned above the two cannot coexist and compilation fails, so I have to delete the config above alternatively from one or the other package.json, depending on which part of my code I'm working on, and thus either frontend or backend don't have eslint/prettier linting.
I'm on VSCode and rely heavily on the error/warning system VSC provides.
Is there a way to keep them both, and eventually have different rules depending on if it's frontend or backend?
I have a project with the following structure
project
├── client
│ └── src
│ ├── index.js
│ ├── and.js
│ ├── some.js
│ ├── other.js
│ └── files.js
├── public
├── server
│ ├── out
│ │ ├── index.js
│ │ └── any.other.dependency.js
│ ├── src
│ │ ├── index.ts
│ │ └── foo.js
│ └── templates
├── shared
│ └── constants.js
└── mutliple.config.files.json
My goal is to have a server with all the server logic inside server/src, which serves different html files from server/templates. I want the server code to use Typescript, and the compiled output should go to server/out.
There's also the client side of the application, which lives in client/src. The logic there is complex enough that I decided to use webpack for bundling. I might even add some react in the future. All this code is compiled by webpcak and the resulting files live in /public.
I also share some constants between the client and server logic, and I decided to put them in ./shared. I might want to add some utilities there in the future, so let's assume it's not just constants.
At some point in the future I'd like to migrate the whole project to TS, but I'm not close to that yet.
How can I achieve this with Typescript?
I have the webpack side sorted out. My problem comes with the TS compiler. I can't manage to get it working because shared is out the compilerOptions.outDir, but if I set it as the whole project folder I end up with a crazy server/out folder structure. Something like server/out/server/src/index.js
My tsconfig.json looks like this:
{
"extends": "#tsconfig/node12/tsconfig.json",
"include": ["server/src/*", "shared/*"],
"exclude": ["node_modules"],
"compilerOptions": {
"allowJs": true,
"noImplicitAny": false,
"outDir": "./server/out/",
"rootDir": "./server/src"
},
}
I'm using pugjs for my project.I was unable to load a css file in the pug template. I'm using the following code
index.pug
link(rel="stylesheet", href="views/styles/products.css", type="text/css")
This is my project structure
Express is not going to serve anything that you don't give permission to. You have to give permission by using express.static middleware.
Put your Static files in a folder then use the express.static middleware like this-
app.use(express.static(path.join(__dirname, 'public')));
For more details refer to https://expressjs.com/en/starter/static-files.html
My directory setup looks something like this:
.
├── app.js
├── bin
│ └── www
├── package.json
├── package-lock.json
├── public
│ ├── images
│ ├── css
│ │ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.pug
├── index.pug
And in the index.pug, we have to use:
html
head
title=homepage
link(rel='stylesheet', href='/views/dashboard/dashboard.css')
body
And in app.js add this line of code:
app.use(express.static(path.join(__dirname, 'public')));
My issue here is incredibly similar if not exactly the same as the one outlined in this issue. Unfortunately, I haven't been able to resolve it using the strategy it provides. So here are my own details:
I am using Create React App, React Router 4, Express, and Heroku and have followed the instructions here with regards to setting up a server with CRA.
Locally, I am able to access routes such as myapp/about, yet after building and pushing to heroku, these 404.
I can navigate to this route via the UI (i.e. by clicking on a menu item that pushes a route onto history), yet am unable to navigate to this route using only my browser's address bar. Furthermore, when I navigate using the UI, I'm not seeing any network activity related to the route such as an /about request. Yet when I change the address bar and hit enter, this yields a network request to said route.
Here are some select snippets from my code:
app.js
<Switch>
<Route exact path="/about" component={About} />
<Route path="/"
render={props => <coolListContainer {...props}/>} />
</Switch>
server.js
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
}
//...what some of my api routes look like:
app.route('/api/verify')
.post( async (req, res) => {
try {
await db.verifyCode(req.body)
res.json('success')
} catch (err) {
res.json(err);
}
}
});
My directory structure as provided by full-stack-react`'s express demo.
└── myapp
├── Procfile
├── README.md
├── client
│ ├── build
│ │ ├── asset-manifest.json
│ │ ├── index.html
│ │ └── static
│ │ ├── css
│ │ │ ├── main.e8c50ca0.css
│ │ │ └── main.e8c50ca0.css.map
│ │ └── js
│ │ ├── main.24fe0ebe.js
│ │ └── main.24fe0ebe.js.map
│ ├── package.json
│ ├── public
│ │ └── index.html
│ ├── src
│ │ ├── About.js
│ │ └── index.js
│ └── styles
│ └── about..css
├── package.json
├── server.js
└── static.json
Per answer given to this post, I've also plopped a static.json file into the root directory.
static.json
{
"root": "client/build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
The above configuration gives me 404s on any route.
Alrighty, I figured this out.
All I needed was to ensure that any request not relevant for my internal API, such as a GET request via the address bar, is routed directly to my index.html file which handles the dynamic routing via React Router. Seems obvious enough now.
Here is the final route in my app.js:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '/client/build/index.html'));
});
I am new to Node.js application development with expressjs framework.
I created a skeleton with expressjs-generator.
This skeleton have following directories and files:
.
├── app.js
├── bin
│ └── www
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.jade
├── index.jade
└── layout.jade
After it: I use the following command to run this application.
set debug=myapp:* & start npm
Now this is successfully running at Port 3000
This shows the homepage with Express Welcome message.
I want to make change in Homepage of my application. How it can be possible?
You can do that by changing the index.jade as #brute_force mentioned. If you are not familiar with jade, you can also add a index.html in the public folder and update the index.html instead.