Express and vue.js are linked.
I have set up a route and when I run Express, it will go to an address different from the vue setting.
Vue index router
import Vue from 'vue';
import Router from 'vue-router';
import Editor from '#/components/Editor';
Vue.use(Router);
export default new Router({
mode: 'history',
routes:[
{
path : '/board',
name : 'Editor',
component : Editor
}
]
})
Vue main.js
import Vue from 'vue';
import App from './App.vue';
import {router} from './routes/index.js';
import axios from 'axios';
import ElementUI from 'element-ui';
import { ElementTiptapPlugin } from 'element-tiptap';
import 'element-tiptap/lib/index.css';
Vue.use(ElementUI);
Vue.use(ElementTiptapPlugin, {
// lang: "zh",
// spellcheck: false,
});
Vue.config.productionTip = false;
Vue.prototype.$http = axios;
new Vue({
render: h => h(App),
router
}).$mount('#app');
Express index router
const express = require('express');
const router = express.Router();
const mssql = require('mssql');
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>Index</p>
<a href='/board'> Go to Vue Page </a>
</body>
</html>
app.js
const createError = require('http-errors');
const fs = require('fs');
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const ejs = require('ejs');
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const apiRouter = require('./routes/api');
const port = 8000; //changed port
app.use(express.static('public'));
app.use(express.static(path.join('node_modules', 'devexpress-richedit', 'dist', 'custom')));
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
// view engine setup
app.set('views', path.join(__dirname, '/views'));
app.set('view engine', 'ejs');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
// app.use(express.static(path.join(__dirname, '/public')));
app.use(express.static(path.join(__dirname, '/')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/api', apiRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`));
my project tree
Express is 8000 port
Connect to'localhost: 8000 /'and Vue's page will appear.
I want express's page to appear when connecting to'localhost:8000/'
And 'localhost:8000/board' doesn't work
I have one more question. How to call express's html file in Vue?
Thanks for your answer
We first need to know how the request flow works in whole express and vue.js.
In your project, you're not running express and vue with same port at the same time.
More clearly, you're using express with 8080 port to host vue.js content.
Express Router Flow
In express, your request match the rule app.get("/", (req, res)= >{res.render("index")})
then express will render the index page for you when you visit the http://localhost:{port}/
And after you add "other" word in your rule app.get("/other", (req, res)= >{res.render("other")})
express will render other page for you when you visit the http://localhost:{port}/other
What if request doesn't match rule?
Express will give you a not found page.
Vue.js Router Flow
When you host the vue output js (we call build.js here) in express server instead of webpack-server.
In your vue project, you setup the vue-router with / and /other-path.
In these paths, vue will render content of / and /other-page.
We assume you use express to host the build.js
And we need the html to include this build.js with following code.
<!-- put this html in project_root/public/{here}-->
<div id="app"></div>
<script src="/build.js"><script>
And we setup the following code to host this html.
app.use("/", express.static(path.resolve(__dirname, "public")))
When we type http://localhost:{port}/, express will give the index.html to browser.
Then you could use website, click link which is <router-link> go to "other-page" which is provide by vue.
BUT, what if you type http://localhost:{port}/other-page in the browser, then push enter button?
Express will give you not found page.
Because express will give you content when you first visit the website.
That means when a request is coming to express, express will give you content by your rule.
If rule doesn't match, express give you not found page.
If rule match, express give you content which you setup.
In the above example, express give you index.html because you setup app.use("/", express.static(path.resolve(__dirname, "public"))).
Then you see the content of index.html in browser.
And then there is a build.js to render the content of vue for you.
But, there is no rule about "other-page" so express give you not found page.
Sum Up
When request is coming ...
express decide the content by your rule.
Not Matched: express give you not found page.
Matched: express give you content by your rule
When request matched, it give you html (at above example).
bowser render the html
html include the build.js
build.js render the content of vue
When you click vue-router link go to other page
There is no real request sent by browser.
It's controlled by your build.js.
When you type url in browser, then push enter bottom.
It goes to step1.
So if your vue.js router and express router have same router path
your express will not give you the vue content when you type url in browser.
Example
We assume your vue output which is called build.js is located in project_root/public/{here}.
There are two routes path "/" and "/vue-content" in your vue-router.
In your express router, you setup like this.
app.use("/", express.static(path.resolve(__dirname, "public")))
app.use("/express-page", (req, res) => {res.render("express-page")})
Then in webpack.config.js
output.publicPath: "/"
output.path: path.resolve(__dirname, "public")
And don't forget the you must have a index.html in project_root/public.
index.html must have script tag including the build.js
Then try to put <a href="/express-page">go to express<a> into your vue content.
Finally, go to http://localhost:8080/, you will see html page which in public.
The build.js render the content for you.
After you click "go to express", browser send the request to express.
Express will render "express-page" for you instead of index.html page.
But, you will find express give you not found page after you type http://localhost:{port}/vue-router in browser and push enter button.
So, how to fix it?
Add the new rule in the end.
app.use("/", express.static(path.resolve(__dirname, "public")))
app.use("/express-page", (req, res) => {res.render("express-page")})
app.use(express.static(path.resolve(__dirname, "public"))) // here
According our sum up step flow, express doesn't have "vue-router" rule.
But, there is a rule which match any request.
app.use(express.static(path.resolve(__dirname, "public")))
So, express will give you index.html
Then build.js will render "vue-router" content for you because vue will get the url to render content by vue-router setting.
Related
I have a react app I built with an express API to interact with mongoDB. I am now trying to set up server side rendering in my server.js file. I can't figure out why but the server rendered string is only being sent in the browser over my API port localhost:3899/api instead of localhost:3000 where my client is being served.
When I curl http://localhost:3899 I get the html string in my console. When I curl http://localhost:3000 I get the public/index.html skeleton.
I have my client and server directories next to each other at the same level.
node_modules
react-ui
server
...
server.js:
import express from 'express';
import path from 'path';
import React from 'react';
import 'ignore-styles';
import ReactDOMServer from 'react-dom/server';
import render from './render';
import App from '../react-ui/src/App';
import mongoose from 'mongoose';
import cors from 'cors';
import bodyParser from 'body-parser';
import Appointment from './model/appointments';
//and create our instances
var app = express();
var router = express.Router();
app.use(express.static(path.resolve(__dirname, '../react-ui/build/static')));
//set our port to either a predetermined port number if you have set
//it up, or 3899
var port = process.env.PORT || 3899;
//db config
mongoose.connect('mongodb://josh11:josh11#ds133162.mlab.com:33162/heroku_tl016m5d');
app.use(cors());
//now we should configure the API to use bodyParser and look for
//JSON data in the request body
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//now we can set the route path & initialize the API
router.get('/', function(request, response) {
response.render(
<!doctype html>
<html>
<header>
<title>My Universal App</title>
</header>
<body>
<div id='app'>${ReactDOMServer.renderToString(<App />)}</div>
<script src='bundle.js'></script>
</body>
</html>
);
});
//Use our router configuration when we call /api
app.use('/api', router);
//starts the server and listens for requests
app.listen(port, function() {
console.log('api running on port' + port);
});
//adding the /appointments route to our /api router
router.route('/appointments')
//retrieve all appointments from the database
.get(function(request, response) {
//looks at our Appointment Schema
Appointment.find(function(error, appointments) {
if (error)
response.send(error);
//responds with a json object of our database appointments.
response.json(appointments)
});
})
//post new appointment to the database
.post(function(request, response) {
var appointment = new Appointment();
//body parser lets us use the req.body
appointment.appointmentTitle = req.body.appointmentTitle;
appointment.appointmentDate = req.body.appointmentDate;
appointment.appointmentTime = req.body.appointmentTime;
appointment.appointmentDescription = req.body.appointmentDescription;
appointment.appointmentDestination = req.body.appointmentDestination;
appointment.appointmentOrigin = req.body.appointmentOrigin;
appointment.travelMode = req.body.travelMode;
appointment.save(function(error) {
if (error)
response.send(error);
response.json({ message: 'Appointment successfully added!' });
});
});
Any guidance would be much appreciated.
To run the application on port defined by environment, try
PORT=3000 node server.js
You have other issue in your code. You have defined the router and mounting the router /api by defining app.use('/api', router). Hence, you are getting 404 whenever you access http://localhost:3000.
To fix the issue, change the router mounting to api.use('/', router).
You can run your API and front-end on the same port by replacing react-scripts with react-app-tools - a slightly altered version of Create React App that adds support for server-side code.
Find more info here: https://github.com/kriasoft/react-app
I'm trying to use the login templates (Took from: 50 Free HTML5 And CSS3 Login Forms For Your Website 201
My directory set up is like this :
-css
|
-- style.css
- js
|
-- index.js
|
index.html
The head of the index.html file looks:
<head>
<meta charset="UTF-8">
<title>Sign-Up/Login Form</title>
<link href='http://fonts.googleapis.com/css?family=Titillium+Web:400,300,600' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
and the body contains the includes scrips:
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="js/index.js"></script>
My node.js looks:
// Import Required Module
var express = require('express')
var app = express()
var bodyParser = require('body-parser')
// css
var path = require('path')
app.use(express.static(path.join(__dirname, 'public')));
// Create instances
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// Get
app.get('/', function (req, res) {
console.log('Get: /');
res.sendFile('LoginTemplate/index.html', {root: __dirname })
})
/*
app.get('css/style.css', function (req, res) {
console.log('Get: css/style.css');
res.sendFile('css/style.css', {root: __dirname })
})
*/
// Listner
app.listen(3001, function () {
console.log('Example app listening on port 3001!')
})
When loading the html file I'm getting the error:
GET http://127.0.0.1:3001/css/style.css
I have tried to look for solution at:
Can not get CSS file
And created the public folder and copy the css folder inside, but it still doesnt work.
How can I load the css & js files ?
// Import Required Module
var express = require('express')
var app = express()
var bodyParser = require('body-parser')
// Create instances
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// Get
app.get('/', function (req, res) {
console.log('Get: /');
res.sendFile('LoginTemplate/index.html', {root: __dirname })
})
app.get('/css/style.css', function (req, res) {
console.log('Get: css/style.css');
res.sendFile('LoginTemplate/css/style.css', {root: __dirname })
})
app.get('/js/index.js', function (req, res) {
console.log('Get: js/index.js');
res.sendFile('LoginTemplate/js/index.js', {root: __dirname })
})
// Listner
app.listen(3001, function () {
console.log('Example app listening on port 3001!')
})
Everything looks good in your code and folder setup. From the URL you are posting (http://127.0.0.1:3001/css/style.css), I am guessing that the error lies in your server instance. Check the definition files and make sure that the server has permission to read css/style.css.
I have run into this problem when the file and folder do not have the right permissions. A quick check for this is running something similar to sudo chmod -R 0777 [path_to_your_project] (linux and Mac systems will use this command). This command gives full access to all users and guests to read, write and execute your files and is a quick way to verify whether the problem is user rights.
I have also run into this same problem when my web server is not correctly configured. In those cases, I had accidentally allowed the web server to share all files in the root folder (eg: /var/www ), but not any sub folders, so (using the example) the folder /var/www/images would be parsed by the web server and seen as an area that is protected. In this case, the Web Server has access, but it refuses to serve the files based on the configuration rules.
I hope one of these two fixes helps direct you down the right path to a solution.
Good luck!
I am trying to build the ToDo app with the MEAN stack and I can't get the Express server to connect to Angular 2. I believe it has something to do with where I have my index.html view relative to the Angular installation, but I can't figure it out.
The error I am getting is the HTML on index.html is rendering but not picking up the logic behind the selector so my assumption is my tags are wrong or something. I have tried every which way to adjust the tags, but I can't get it to work when running server.js. I know it is something silly but been working on this for a while.
Server.js
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var todos = require('./routes/todos');
var app = express();
// View Engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static(path.join(__dirname,'client'))); //folder where angular will be
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/', index);
app.use('/api/v1/', todos);
app.listen(3000, function(){
console.log('Server started on port 3000...');
});
Index.html (in Views folder)
<!DOCTYPE html>
<html>
<head>
<title>Angular QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="src/styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="src/systemjs.config.js"></script>
<script>
System.import('src/main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent FROM SERVER SIDE content here ...</my-app>
</body>
</html>
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
#NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>`,
})
export class AppComponent { name = 'Angular'; }
Below are the two errors I am getting in the console:
GET http://localhost:3000/src/app/app.module 404 (Not Found)
scheduleTask # zone.js:1960 ZoneDelegate.scheduleTask # zone.js:349
(404 Not Found) loading http:…pp.module" from
http://localhost:3000/src/main.js", originalErr:
ZoneAwareError}
Any help would be much appreciated, I can't get past this.
It is not liking something about the reference in this line and getting lost somewhere in zone.js, but I can't get it right. I am using the starter kit from angular.io and using their file layout.
System.import('src/main.js').catch(function(err){ console.error(err); });
I was able to fix by adding two more static routes to the express server so it looked in every folder.
app.use(express.static(path.join(__dirname, 'client'))); // folder where angular will be installed
app.use(express.static(path.join(__dirname, 'client', 'src')));
app.use(express.static(path.join(__dirname, 'client', 'src', 'app')));
This fixed the issue.
I have encountered the same problem with the new version of Quickstart. The fact that it has a different structure (src folder added) affects how express will behave. In my scenario I have NOT altered this portion.
System.import('src/main.js').catch(function(err){ console.error(err); });
Instead I left it as default (I believe angular handles where to look for it).
System.import('main.js').catch(function(err){ console.error(err); });
I have added one more static route. Make sure you have both, one of them will not suffice.
app.use(express.static(path.join(__dirname, 'client')));
app.use(express.static(path.join(__dirname, 'client/src')));
if you are following the TRAVERSY MEDIA: (original Source is EDUONIX)
https://www.youtube.com/watch?v=PFP0oXNNveg&t=2304s
after creating the 'client' folder. Skip the whole JSON Part.
Open Terminal
git clone https://www.github.com/angular/quickstart client
npm install
npm start (this will give you the complete start of the angular front-end)
ctrl + C (close the webserver)
npm run build
server.js
var express = require ('express');
var path = require ('path');
var bodyParser = require ('body-parser');
var index = require ('./routes/index');
var todos = require ('./routes/todos');
var app = express();
//View Engine
app.use(express.static( path.join(__dirname, 'client') ) );
app.use(express.static( path.join(__dirname, 'client/src')));
app.use(express.static( path.join(__dirname, 'client/bower_components')));
app.set('views', path.join(__dirname, 'client/src') );
app.set('view engine', 'ejs');
app.engine ('html', require('ejs').renderFile );
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false} ));
app.use('/', index);
app.use('/api/v1', todos);
app.listen(3000, function() {
console.log ('server started on port 3000');
/routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index.html');
});
module.exports = router;
Last but not the least:
make sure this route would execute:
http://localhost:3000/api/v1/todos
yes? (you did it)
I am learning Mean.js stack, and try to build an app. I have installed Express, and it works. When I tried to configure my static file ( html, js, images, etc.), then things broke.
Here are my files:
server.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + "public"));
app.listen(3000);
console.log('Server running on port 3000');
My html file is very simple :
<!DOCTYPE>
<html>
<head>
<title>Contact List App</title>
</head>
<body>
<h1>Contact List App</h1>
</body>
</html>
So when I start the server : node server.js, and then I type http://localhost:3000/ in the browser, I get the "Cannot Get" error.
Where is the problem?
__dirname doesn't have a trailing slash, so you need to provide one yourself when building the static root:
app.use(express.static(__dirname + "/public"));
^ this needs to be there
You need to make sure the route exists. Also, it is a better practice to use path for joining strings. Also, make sure the directory public exists and the file index.html is inside that folder.
var path = require('path');
var express = require('express');
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res){
res.render('index.html');
});
app.listen(3000);
console.log('Server running on port 3000');
Is there any way I can always serve the same file?
So, if they go to website.com/ajsdflkasjd it still serves the same file as website.com/asdnw
I would like to do this using express with node.
The file I have is a static html file, not a jade file.
By the way, the reason I'm wanting to do this, in case you were wondering, is I have an angularjs app that handles all the routing for me. So, all I need to do is serve that one page, and it will take care of the rest.
Thanks in advance!
new answer
const app= require('express')()
// static file serve
app.use(express.static(__dirname))
// not found in static files, so default to index.html
app.use((req, res) => res.sendFile(`${__dirname}/index.html`))
app.listen(3000)
old answer
var express = require('express');
var bodyParser = require('body-parser')
var path = require('path')
var app = express();
// url encoding
app.use(bodyParser.urlencoded({extended:false}));
// gzip
// redirect all html requests to `index.html`
app.use(function (req, res, next) {
if (path.extname(req.path).length > 0) {
// normal static file request
next();
}
else {
// should force return `index.html` for angular.js
req.url = '/index.html';
next();
}
});
// static file serve
app.use(express.static(__dirname))
app.listen(3000)
Below is what I'm using express with angularjs in my project. It will always send index.html unless the browser requests resource files (images, css, js, etc.) which contains extname.
var express = require('express');
var app = express();
app.configure(function () {
// url encoding
app.use(express.urlencoded());
// gzip
app.use(express.compress());
// redirect all html requests to `index.html`
app.use(function (req, res, next) {
if (path.extname(req.path).length > 0) {
// normal static file request
next();
}
else {
// should force return `index.html` for angular.js
req.url = '/index.html';
next();
}
});
// static file serve
app.use(express.static(__dirname));
});
Basic configuration for Express 4 is:
var express = require('express');
express()
.get(/.*/, function(req, res) {
res.sendFile('index.html', {
root: __dirname
});
})
.listen(8080);
Working example
Those snippets with GZip, BodyParser etc. are pretty cool, but I think over-complicated if you want to just test your single page app. Of course you can add all this "production stuff" when it starts to be needed.
Read more:
sending files
routing
Here a simple implementation with ExpressJs to create a virtual host and whenever return the index.html
var express = require('express');
var app = express();
var vhost = require('vhost');
// Function to create virtualhost
function createVhost(domain,rootDirectory){
var exp = express();
exp.use(express.static(rootDirectory));
exp.get(/.*/,function(req,res){
res.sendFile('index.html',{root:rootDirectory});
})
app.use(vhost(domain,exp));
}
// Virtual Host to create
createVhost('example.com','/home/[user]/[www]/[example.com]');
createVhost('othersite.com','/home/[user]/[www]/[othersite.com]');
// Start Server
app.listen(80,function(){
console.log('Node server on port 80');
});
Remember:
Add the domains in the "/etc/host" (in linux)
127.0.0.1 example.com
127.0.0.1 othersite.com
And run in the terminal the "app.js" with "sudo" for port 80
~/home/[server]$ sudo node app.js
You can do this in both angular as well as node side.
In Node side you can do something like this:
res.sendfile('<ur html file path');
In Angular if you using ui-router you can make use of
$urlRouterProvider.otherwise('/otherwise');
and this otherwise state needs to be defined as well
$stateProvider
.state("otherwise", { url : '/urPage'...})
If you using ngRoute, you can do
$routeProvider.otherwise({redirectTo: '/urPage'});
UPDATE
Since your routers are not configured to show a default urPage, in the server you can have something as:
var app = express.createServer();
app.get('/urPage',function(req,res){
res.sendfile('<ur html page>');
});