I've created a site with create-react-app that I build in ./client/build
and serve with express.
Using express, I also setup 2 basic API routes that work well in dev (localhost).
I build the client with react-scripts
Then I manually set the environment to production to build locally the server with webpack
Finally I push my code to my GitLab repo, and it triggers the deploy automatically.
Used Netlify deploy's settings :
Build command: Not set
Publish directory: client/build
When I try to use one of my API routes, I get an error 404 ...
My project structure is like this :
| package.json
| server.js
| webpack.config.js
+---API
| dbHandler.js
| routesHandler.js
+---client
| | package.json
| +---src
| | | App.js
| | | ...
| +---node_modules
| +---public
| | index.html
| | manifest.json
| | _redirects
| \---build
| | index.html
| | manifest.json
| | _redirects
| | asset-manifest.json
| | favicon_rings.ico
| | service-worker.js
| \---static
| +---media
| | ...
| +---js
| | main.1e7ccdbf.js
| | main.1e7ccdbf.js.map
| \---css
| main.fc8f2d26.css
| main.fc8f2d26.css.map
+---public
| _redirects
\---bundles
bundle.js
Extract from ./package.json
:
"main": "server.js",
"homepage": "https://custom.netlify.com",
"scripts": {
"start": "node server.js",
"build": "webpack --config webpack.config.js",
"postinstall": "npm run build",
"start:dev": "nodemon -e js --exec babel-node -- ./server.js"
}
./client/package.json
:
"homepage": "https://custom.netlify.com",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build && cp build/index.html build/404.html",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
./client/build/_redirects
and ./public/_redirects
:
# Redirects from what the browser requests to what we serve
/* /index.html 200
./server.js
:
import webpackDevMiddleware from "webpack-dev-middleware";
import webpackHotMiddleware from "webpack-hot-middleware";
import routesHandler from "./API/routesHandler";
import config from "./webpack.config";
import bodyParser from "body-parser";
import webpack from "webpack";
import express from "express";
import path from "path";
const port = process.env.PORT || 5000;
const ExpressServer = express();
const CLI_BUILD_DIR = path.join(__dirname, "client/build");
const HTML_BUNDLE = path.join(CLI_BUILD_DIR, "index.html");
const compiler = webpack(config);
const isDevelopment = process.env.NODE_ENV === "development";
ExpressServer.use(bodyParser.urlencoded({ extended: true }));
ExpressServer.use(bodyParser.json());
ExpressServer.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
if (isDevelopment) {
ExpressServer.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
})
);
ExpressServer.use(webpackHotMiddleware(compiler));
} else {
// Serve static files from the React app
ExpressServer.use(express.static(CLI_BUILD_DIR));
}
// Define API routes
var router = express.Router();
router.post("/register", routesHandler.register);
router.post("/login", routesHandler.login);
// Put all API endpoints under '/API'
ExpressServer.use("/API", router);
// All other routes will be directed to the main page of user interface
ExpressServer.get("/", (req, res) => res.sendFile(HTML_BUNDLE));
ExpressServer.get("*", (req, res) => res.redirect(301, "/"));
// Start the server
ExpressServer.listen(port, function() {
console.log("Express server listening on http://localhost:" + port);
});
./webpack.config.js
:
const path = require('path');
const webpack = require('webpack');
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
module.exports = {
entry: [
'webpack-hot-middleware/client',
'./API/routesHandler.js',
'./API/dbHandler.js',
'./server.js'
],
externals: {
jquery: 'jQuery',
'react/addons': 'react',
'react/lib/ExecutionEnvironment': 'react',
'react/lib/ReactContext': 'react',
},
output: {
path: path.resolve(__dirname, 'bundles'),
filename: 'bundle.js',
publicPath: '/public',
sourceMapFilename: 'bundle.map',
},
devtool: process.env.NODE_ENV === 'production'
? undefined : 'cheap-module-eval-source-map',
resolve: {
modules: ['node_modules', './client/build', './API', '.'],
extensions: ['.js', '.jsx', '.css'],
},
module: {
rules: [
{
test: /(\.js$|\.jsx$)/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['react', 'es2015', 'stage-0', 'airbnb'],
},
},
],
},
{
test: /(\.css$|\.scss$)/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
}
}
],
},
node: {
console: false,
fs: 'empty',
fsevents: 'empty'
},
plugins: [
new webpack.IgnorePlugin(/fs/)],
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
minimize: true,
compressor: {
warnings: false,
},
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
},
}),
],
};
js on netlify. AWS's serverless Lambda functions open a world of possibilities for running on-demand, server-side code without having to run a dedicated server. Netlify lets you deploy serverless Lambda functions without an AWS account, and with function management handled directly within Netlify.
Netlify also securely stores credentials required for your frontend to connect to remote backend services and can also proxy API requests through to your own domain.
js express RESTful API, you have many alternatives of hosting platforms such as Heroku, digital ocean, aws, gcp e.t.c which is perfectly fine.
Netlify is for static file hosting - you can't deploy an Express application to it, only your frontend. You'll need to use a different service (such as DigitalOcean or Heroku) for your API hosting. You could potentially then route traffic to that API server via Netlify using redirects if you want to use their CDN for response caching.
Edit: This is no longer entirely true - Netlify now also has support for deploying AWS Lambda functions, allowing JavaScript and Go to be run on the server-side.
With Netlify's addition of support AWS Lamdba functions earlier this year, this is actually quite possible now. Here are some resources for those who find this question now.
https://www.netlify.com/docs/functions/
https://www.netlify.com/blog/2018/09/13/how-to-run-express.js-apps-with-netlify-functions/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With