How do I configure Webpack for production in my React app? (Github pages)

1k views Asked by At

My React app throws 404 errors in production when accessing static files (stylesheets, utilities, and more). The development environment works fine. After debugging for several days and further research I believe it's a webpack pathing issue as my understanding of build path and webpack.output is still lacking despite my research on webpack.js.org. After referencing other posts, I still can't grasp this final concept for bundling applications. All help is appreciated. See below for Things tried, and Posts referenced, and Notes for my process. Thank you.

Things tried:

  1. Added "homepage" property in package.json pointing to "https://my_ghub_username.github.io/project_repo/"

  2. Changed "homepage" property to "."

  3. Changing React router to <HashRouter/> ensuring it imported correctly.

  4. Pushed my latest changes to main before deploying my app to GH pages again

  5. Added package.json scripts to pre-deploy, deploy, && build

Posts/Guides Referenced

  1. How to deploy a React app to GitHub Pages
  2. https://create-react-app.dev/docs/deployment/#github-pages-https-pagesgithubcom
  3. Can't deploy webpack to gh-pages (react app)

I attached snippets of relevant code package.json(I), webpack.dev/prod/common.js(II), index.html(III), file tree(IV), and errors(V) in chrome tools.

(I)

{
  "name": "digital-nomad",
  "version": "1.2.2",
  "description": "An immersive experience to experience life in major cities!",
  "main": "index.jsx",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist",
    "build": "webpack --config webpack.prod.js",
    "start": "webpack serve --config webpack.dev.js"
  },
  "homepage": ".",
  "dependencies": {
    "@babel/core": "^7.12.3",
    "@babel/preset-env": "^7.12.1",
    "@babel/preset-react": "^7.12.1",
    "babel-loader": "^8.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "gh-pages": "^3.1.0",
    "googleapis": "^64.0.0",
    "inline-source-map": "^0.6.2",
    "mini-css-extract-plugin": "^1.3.2",
    "react": "^16.14.0",
    "react-dom": "^16.14.0",
    "react-redux": "^7.2.1",
    "react-router-dom": "^5.2.0",
    "redux": "^4.0.5",
    "webpack-cli": "^4.1.0",
    "webpack-merge": "^5.4.1"
  },
  "devDependencies": {
    "css-loader": "^5.0.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "html-webpack-plugin": "^4.5.0",
    "style-loader": "^2.0.0",
    "webpack": "^5.2.0",
    "webpack-dev-server": "^3.11.0"
  }
}

(IIA)

const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')



module.exports = merge(common, {

  mode: 'development',

  devtool: 'inline-source-map',

  devServer: {
    contentBase: './',
    compress: true,
    open: true,
    port: 8080,
    watchContentBase: true,
    historyApiFallback: true,
  }

})

(IIB)

const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')


module.exports = merge(common, {

  mode: "production",

  devtool: "source-map",

})

(IIC)

const path = require('path')

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
  title: 'Production',
  template: __dirname + '/index.html',
  filename: 'index.html',
  inject: 'body',
  favicon: "favicon.png"
})


module.exports = {

  entry: path.resolve(__dirname, "src", "index.jsx" ),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: './'
  },

  module: {
    rules: [
      { test: /\.jsx?$/, exclude: /(node_modules)/, 
        use: {
          loader: 'babel-loader',
          options: { presets: ['@babel/env', '@babel/react'] }
        },
      }, 
      { test: /\.css$/i, 
        use: [ 
          {
            loader: MiniCssExtractPlugin.loader,
            options: { publicPath: '../' }
          }, 
          'css-loader'
        ],
      }
    ]
  },

  plugins: [ 
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin(),
    HTMLWebpackPluginConfig 
  ],

  resolve: {
    extensions: [".js", ".jsx", ".css", "*"]
  },

  performance: {
    hints: false
  },

  stats: {
    errorDetails: true,
    warnings: true,
    colors: true,
  },


};

(III)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="icon" type="image/png" href="favicon.png">

    <!-- youtube video API -->
  <script rel='preload' src="https://www.youtube.com/iframe_api"></script>
    <!-- youtube data API -->
  <script rel='preload' src="https://apis.google.com/js/api.js"></script>

  <script defer src="./src/utils/YTVideoAPI.js"></script>
  <script defer src="./src/utils/YTDataAPI.js"></script>

  <script src="/dist/bundle.js"></script>
  
  <link rel="stylesheet" type="text/css" href="./src/stylesheets/player.css">
  <link rel="stylesheet" type="text/css" href="./src/stylesheets/root.css">
  <link rel="stylesheet" type="text/css" href="./src/stylesheets/controls.css">

  <title>Digital Nomad</title>
</head>
<body>.
  
  <div id="root"></div>
  
</body>
</html>

(IV)

FileTree

(V)

GET https://username.github.io/project_name/src/stylesheets/player.css net::ERR_ABORTED 404

Note

I tried my hand over the past couple of days with alternative solutions like utilizing a 404 page to redirect to my app while still using Browser router as a potential solution but not understanding this last aspect of webpack is killing me since I know I can use webpack to my advantage. ( I really want to better conceptualize webpack pathing to improve existing apps ).

Lastly, any feedback on code quality, convention, and implementation is extremely welcome.

0

There are 0 answers