Webpack & NGINX configuration for React app with set path prefix - reactjs

I'm working on a React app and I have it working when I deploy it as a Docker container, in a Rancher cluster, to what I'll call a "normal" endpoint. Meaning if I set up the endpoint to be test.site.com, everything works fine. The problem is my company is insisting on using path to direct traffic to different services. For example, test.site.com/my-site will direct traffic to my React app, but test.site.com/other-site directs traffic to another service. I'm having an issue where when I deploy my site to test.site.com/my-site, my app can't seem to resolve some of its assets. Opening the console in the browser gives errors such as:
GET https://test.site.com/cesium/Cesium.js net::ERR_ABORTED 405
GET https://test.site.com/cesium/Widgets/widgets.css net::ERR_ABORTED 404
GET https://test.site.com/bundle.js net::ERR_ABORTED 404
(Cesium is a library I'm using in my app https://cesium.com/blog/2018/03/05/integrating-cesium-and-react/)
I've only recently started working with webpack, so I think there's probably some configuration there to fix this? Here's the relevant config files.
webpack.config.js
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const HtmlPlugin = require('html-webpack-plugin')
const HtmlTagsPlugin = require('html-webpack-tags-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const dotenv = require('dotenv')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
publicPath: '/',
},
resolve: {
modules: [path.join(__dirname, 'src'), 'node_modules'],
alias: {
react: path.join(__dirname, 'node_modules', 'react'),
},
extensions: ['.jsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
],
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
],
},
devServer: {
historyApiFallback: {
index: '/',
},
},
externals: {
cesium: 'Cesium',
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
new webpack.DefinePlugin({
'process.env': JSON.stringify(dotenv.config().parsed), // it will automatically pick up key values from .env file
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'node_modules/cesium/Build/Cesium',
to: 'cesium',
},
],
}),
new HtmlPlugin({
template: './src/index.html',
}),
new HtmlTagsPlugin({
append: false,
tags: ['cesium/Widgets/widgets.css', 'cesium/Cesium.js'],
}),
new webpack.DefinePlugin({
CESIUM_BASE_URL: JSON.stringify('/cesium'),
}),
],
}
Dockerfile
FROM node:14-slim AS builder
ENV NODE_ENV production
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
FROM nginx:1.21.0-alpine as production
ENV NODE_ENV production
COPY --from=builder /app/build /usr/share/nginx/html
RUN echo $(ls -1 /usr/share/nginx/html)
RUN chown nginx:nginx -R /usr/share/nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN echo $(ls -1 /etc/nginx/conf.d/)
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

Related

GCP 500 Erroring despite files uploaded

I am trying to deploy a React app for the first time and can't seem to figure out why it is not working...
Here is what I have tried:
git clone [repo url]
cd repo/client
npm i
npm build
cd build
vim app.yaml
Entered the following:
env: standard
runtime: nodejs12
handlers:
- url: /
static_files: build/\1
upload: build/.*
gcloud app deploy app.yaml --verbosity=debug
Output:
INFO: Manifest: [{'index.html': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/226a7f7ca6cf647c5457b709cef629bb950fbc9a', 'sha1Sum': '226a7f7ca6cf647c5457b709cef629bb950fbc9a'}, '961.index.bundle.js': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/907d0e7384a3b3060ba5b0bf522d5c6e99f38d39', 'sha1Sum': '907d0e7384a3b3060ba5b0bf522d5c6e99f38d39'}, '1': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/12de9963495774159595601cd57e64c1febb1e9a', 'sha1Sum': '12de9963495774159595601cd57e64c1febb1e9a'}, 'app.yaml': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/e3979db38f5ace413d6dff3d8f7e30bda5922438', 'sha1Sum': 'e3979db38f5ace413d6dff3d8f7e30bda5922438'}, 'index.bundle.js.LICENSE.txt': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/e74ccdb144d7d0ada75f8115a86b4c93444238cf', 'sha1Sum': 'e74ccdb144d7d0ada75f8115a86b4c93444238cf'}, 'index.bundle.js': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/4bca86ed5f442588b4cd5a7dc59719afe5c67015', 'sha1Sum': '4bca86ed5f442588b4cd5a7dc59719afe5c67015'}, 'source-context.json': {'sourceUrl': 'https://storage.googleapis.com/staging.reactfrontend-336116.appspot.com/a0d08448a753f65abae14090837cf7c12a173cad', 'sha1Sum': 'a0d08448a753f65abae14090837cf7c12a173cad'}}]
As you can see the all files are correctly uploaded (there are no assets), but when I access the URL I get a 500 Server error: "The server encountered an error and could not complete your request."
I'm not really sure what I've done wrong... I can run the React app locally without any issues
Webpack:
const HtmlWebpackPlugin = require('html-webpack-plugin');
// hot reload CSS:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
module.exports = {
entry: './src/index.jsx',
output: {
path: path.join(__dirname, 'build'),
filename: 'index.bundle.js',
assetModuleFilename: 'images/[hash][ext][query]'
},
target: 'web',
devServer: {
historyApiFallback: true,
hot: true,
open: true,
port: 3000
},
performance: {
hints: false
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
type: 'asset/inline'
},
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [new MiniCssExtractPlugin(), new HtmlWebpackPlugin({ template: './src/index.html' })]
};

Why does %PUBLIC_URL% not get replaced in Webpack bundled index.html?

I am trying to deploy the front-end of my web application, but when I deploy to my hosting platform (currently AWS Amplify/S3) - no content displays on the website
I created the application using create-react-app, so the project structure follows their standard (public, src folders etc.).
When I run the application locally it works fine.
From the console errors, and looking at the index.html page that is generated by webpack, it looks like it is not replacing the %PUBLIC_URL% field that should be replaced with the public directory on build.
Please can someone explain how to fix this issue?
I have included my webpack.config file below and the full repo can be found here
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const config = {
entry: ['react-hot-loader/patch', './src/index.js'],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.svg$/,
use: 'file-loader',
},
{
test: /\.png$/,
use: [
{
loader: 'url-loader',
options: {
mimetype: 'image/png',
},
},
],
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: 'file-loader',
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'react-dom': '#hot-loader/react-dom',
},
},
devServer: {
contentBase: './build',
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./public/index.html'),
}),
],
}
module.exports = config
Turns out this was an issue with me trying to add a custom Webpack configuration to a create-react-app project.
I've removed the Webpack config now, and instead used the dist files created when using the create-react-app build process.

Why i get hashed .jpeg file when running 'npm run build' with webpack

Im a new beginner on develop react app.
Im trying to figure out how to set up my webpack.config.js file.
I have following ended up with this structure as you can see on the picture link below.
My question is: When im running 'npm run build' , its hashing the picture and put it into the /dist folder. How can i configure so it does not?
Because im using copyWebpackPlugin() to copy my images and push it to the dist folder, but i dont want the picture which i marked with arrow.
If anyone have some advice just bring it on.
This is how my webpack.config.js file look like:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader"
},
{
test: /\.s?css$/,
loader: ["style-loader", "css-loader"]
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: "url-loader?limit=100000"
}
]
},
resolve: { extensions: [".js", ".jsx"] },
output: {
path: path.resolve(__dirname, "dist/"),
filename: "bundle.js"
},
devtool: "cheap-module-eval-source-map",
devServer: {
contentBase: path.join(__dirname, "public/"),
proxy: {
"/api/*": {
target: "http://localhost:3000/",
secure: "true"
}
},
port: 4000,
publicPath: "http://localhost:4000/dist/",
hotOnly: true,
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./public/index.html"
}),
new CopyWebpackPlugin([{ from: "public/images", to: "images" }])
]
};
I would suggest instead of copy-webpack-plugin use file-loader to copy images
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [{
loader: 'file-loader',
options: {
name: 'images/[name].[ext]',
}
}]
}
if you want hash instead of name
name: 'images/[hash].[ext]',
Package
npm install --save-dev file-loader
It is because the url-loader has a default fallback to file-loader. So if your image is bigger than the limit you have set for url-loader, it does not rewrite the image to base64 data:image in your css, instead gives it to file-loader and it copies that image to your dist folder (output path).
So if you do not want this, disable the fallback option for url-loader
But I also think you should have configure your webpack to copy the files with file-loader properly instead that copy plugin. But you know...
I would give you an example based on your config but I am currently on mobile so I can't code right now.

ReactJS App on PHP backend - how to hot reload on local machine?

I am developing a ReactJS-App that gets served by a PHP backend. On my local machine I set up MAMP with a virtual host pointing to my project's root and I use webpack to bundle my React-App.
Since I really enjoy working with hot reloading I now try to use the webpack dev server to proxy MAMP and benfit from its react hot loading capabilities.
I haven't been able to get it working yet and I hope for someone to help me with the configuration. Or isn't my approach basically working? Anyway, I'll be happy if you help me out with this. Thanks in advance! Here's my webpack config so far:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
module.exports = {
devtool: 'cheap-module-source-map',
devServer: {
port: 3000,
proxy: {
'*': {
target: 'http://my-virtual-host.dev:8888/',
}
}
},
entry: [
'./src/app.jsx'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: 'http://localhost:3000/build/'
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
loaders: [
{
enforce: 'pre',
test: /\.jsx?$/,
include: [
path.resolve(__dirname, 'src'),
],
loader: 'eslint-loader',
},
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, 'src'),
],
loader: 'react-hot-loader'
},
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, 'src'),
],
loader: 'babel-loader',
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: { importLoaders: 1 },
},
'postcss-loader',
],
}),
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new ExtractTextPlugin('bundle.css'),
new StyleLintPlugin({
configFile: '.stylelintrc',
context: 'src',
files: '**/*.pcss'
})
]
};
Okay, I found the solution! My fault: I was thinking that my webpack dev server should "proxy" every request to MAMP and return its response. Putting in the other way around solved my Problem: MAMP serves my PHP Application and the webpack dev server only its assets.
When in development mode my PHP Application links assets to the webpack dev server (this discussion around a github issue helped me a lot: https://github.com/webpack/webpack-dev-server/issues/400).
Now, the main attributes I changed in my webpack config are:
module.exports = {
devServer: {
proxy: {
'*': {
target: 'http://my-virtual-host.dev:8888/',
changeOrigin: true,
}
}
},
entry: [
'webpack-dev-server/client?http://localhost:8080/',
'webpack/hot/only-dev-server', // Enable hot reloading
'./src/app.jsx'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: 'http://localhost:8080/build/'
},
}
Linking assets for example to http://localhost:8080/build/app.js, the proxy settings and the output.publicPath did the trick. Hot reloading works fine.
Although it works for me now I'm still interessted in your thoughts!

Configure react webpack for deploy

need a little help.
We had tried to deploy a react project, but we are unable to configure it.
We use: es6, webpack, redux, react, babel.
this is webpack base:
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export default {
entry: './app/app.js',
output: {
path: './app/App/dist',
filename: '/bundle.js',
},
module: {
loaders: [
{
test: /\.json$/,
loader: 'json',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass'),
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('css!sass'),
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.svg$/,
loader: 'babel?presets[]=es2015,presets[]=react!svg-react',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './app/App/index.html',
}),
new ExtractTextPlugin('/app/App/css/default.css', {
allChunks: true,
}),
],
};
webpack dev:
import webpack from 'webpack';
import baseConfig from './webpack.config.base';
const config = {
...baseConfig,
debug: true,
devtool: 'cheap-module-eval-source-map',
plugins: [
...baseConfig.plugins,
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
colors: true,
historyApiFallback: true,
inline: true,
hot: true,
},
};
export default config;
webpack prod:
import webpack from 'webpack';
import baseConfig from './webpack.config.base';
const config = {
...baseConfig,
plugins: [
...baseConfig.plugins,
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compressor: {
screw_ie8: true,
warnings: false,
},
}),
],
};
export default config;
This is our actual webpack, we are trying to deploy the project with it, but does not work.
Does anyone have an idea how to configure it?
So, it's a server problem probably. You need a HTTP server in order to server the static files (your app basically). I recommend the Ngxin, very easy to configure and use.
After install nginx, delete the /etc/nginx/sites-enable/default file and create a new one (you can use whatever name you want here). Here's the config I use:
server {
listen 80;
listen [::]:80;
server_name example.com;
location / {
root /var/html/myProject/;
try_files $uri /index.html;
}
}
after that, restart nginx and should be ready to go.
for webpack, I have a simpler config that works well:
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isProd = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() == 'production';
const plugins = [
new ExtractTextPlugin(isProd ? 'bundle.[hash].css' : 'bundle.css', { allChunks: true }),
new HtmlWebpackPlugin({
template: 'index.html',
inject: 'body',
filename: 'index.html'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
];
const prodPlugins = [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
];
module.exports = {
devtool: isProd ? 'cheap-module-source-map' : 'eval',
entry: [
'./src/index.jsx'
],
output: {
path: isProd ? path.join(__dirname, 'dist') : __dirname,
publicPath: '/',
filename: isProd ? 'bundle.[hash].js' : 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
},
{
test: /\.(scss|css|sass)$/,
loader: ExtractTextPlugin.extract('css!sass')
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url'
},
{
test: /\.html$/,
loader: 'html'
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
},
plugins: isProd ? prodPlugins.concat(plugins) : plugins
};
A few points:
I'm using SASS
Check the path's before run anything
To compile for production, just run NODE_ENV=production webpack -p
I'm using a few plugins for Uglify JS and compress files.
I think that's it! Cheers!
sure I think the fastest way to solve your problem is to click on this link:
React starter kit
and select any starters that matches your technologies!
I think you are looking for this one : react-boilerplate

Resources