'Is there a way to dynamically pass variables to webpack static react website?
Issue
I am trying to make a static React application with one dynamic configuration value (API_URL). I would like the container to be dynamic so that I can just switch a single file or option and change the URL. What are my options?
I found this StackOverflow article regarding webpack and dotenv.
webpack.prod.ts
import path from 'path'
import { Configuration, DefinePlugin, NormalModuleReplacementPlugin } from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
import * as dotenv from 'dotenv'
const CopyPlugin = require('copy-webpack-plugin');
const config: Configuration = {
mode: 'production',
entry: {
main: './src/index.tsx',
'pdf.worker': path.join(__dirname, '../node_modules/pdfjs-dist/build/pdf.worker.js'),
},
output: {
publicPath: '/',
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.(ts|js)x?$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript',
],
},
},
},
{
test: /\.(sa|sc|c)ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
// * https://github.com/sass/node-sass#outputstyle
outputStyle: 'compressed',
},
},
},
{
loader: 'postcss-loader', // postcss loader needed for tailwindcss
options: {
postcssOptions: {
ident: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: '../fonts',
},
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
new NormalModuleReplacementPlugin(
/^pdfjs-dist$/,
(resource) => {
// eslint-disable-next-line no-param-reassign
resource.request = path.join(__dirname, '../node_modules/pdfjs-dist/webpack.js')
},
),
new CopyPlugin({
patterns: [
{ from: 'public/images', to: 'images' },
],
}),
// Environment Variable for Build Number - Done in NPM scripts
// Super helpful article
// * https://stackoverflow.com/questions/55185601/webpack-process-env-undefined-using-defineplugin-and-dotenv
new DefinePlugin({
...Object.entries(dotenv.config({ path: '/env/.env' }).parsed || []).reduce((acc, curr) => ({ ...acc, [`${curr[0]}`]: JSON.stringify(curr[1]) }), {}),
VERSION_NUMBER: JSON.stringify(process.env.VERSION_NUMBER),
}),
new ForkTsCheckerWebpackPlugin({
async: false,
}),
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
}),
// The CleanWebpackPlugin plugin will clear out the build folder.
new CleanWebpackPlugin(),
],
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000,
},
optimization: {
minimize: true,
minimizer: [
// For webpack@5 you can use the `...` syntax to extend existing minimizers
'...',
],
},
};
export default config
Dockerfile
# Multi-stage Docker file
# 1) Build the node project with the latest version of node
# 2) NGNIX to serve the production front end packed via webpack
# Stage 1: Building the application
FROM node:latest AS build
ARG VERSION_NUMBER
ENV VERSION_NUMBER ${VERSION_NUMBER}
WORKDIR /app
# Copy the app to the working directory on the image
COPY . /app
# Install node modules and build application
RUN yarn install && yarn run build
# Stage 2: Serve content using NGINX Web Server
FROM nginx:latest AS click-n-file
ENV NODE_ENV production
WORKDIR /usr/share/nginx/html
# Remove default nginx static assets
RUN rm -rf ./*
# Copy static assets from builder stage
COPY --from=build /app/build .
# Expose port 80 out of container
EXPOSE 80
# Containers run nginx with global directives and daemon off
ENTRYPOINT ["nginx", "-g", "daemon off;"]
Additional Notes:
- I am using Azure
- I am using Pipelines to build this container but have many customers with different URLs
- I am able to define docker environment variables
Things I have tried
- Added dotenv but not sure how to put one (a .env file) in a production container
- Looked at putting a json configuration in the public folder (then switching it out in prod) - but importing it in code is difficult
- Tried exposing process.env in webpack (didn't get it to work)
I have not changed the docker file or looked at docker-compose
If there is any additional information I can provide let me know. Thanks!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
