title: Spring Boot + React Webpack configuration
body: <p>So I have a Spring boot and Java based REST API project that required a React frontend. So I used <code>create-react-app</code> to generate a simple react project that I could import. Here's the project folder structure:</p>
  
  <pre><code>FooApplication
  ├── build.gradle
  ├── package.json
  ├── node_modules/
  ├── src/
      ├── main/
          ├── java/
          ├── resources/
          └── webapp/
              ├── app/
                  ├── App.js
                  ├── index.js
                  └── serviceWorker.js
              └── index.html
      └── test
  ├── webpack/
      ├── utils.js
      └── webpack.config.js
  </code></pre>
  
  <p>Here's my <code>package.json</code>:</p>
  
  <pre><code>{
    "name": "boss-management-service",
    "version": "0.1.0",
    "private": true,
    "dependencies": {
      "base-href-webpack-plugin": "2.0.0",
      "browser-sync": "2.26.7",
      "browser-sync-webpack-plugin": "2.2.2",
      "copy-webpack-plugin": "5.0.3",
      "html-webpack-plugin": "3.2.0",
      "react": "^16.8.6",
      "react-dom": "^16.8.6",
      "react-scripts": "3.0.1",
      "start": "^5.1.0",
      "webpack": "4.37.0",
      "webpack-cli": "3.3.6",
      "write-file-webpack-plugin": "4.5.0"
    },
    "scripts": {
      "start": "NODE_ENV=development BABEL_ENV=development",
      "build": "npm run start &amp;&amp; npm run webpack -- --config webpack/webpack.config.js",
      "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js",
      "test": "react-scripts test",
      "eject": "react-scripts eject"
    },
    "eslintConfig": {
      "extends": "react-app"
    },
    "browserslist": {
      "production": [
        "&gt;0.2%",
        "not dead",
        "not op_mini all"
      ],
      "development": [
        "last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
      ]
    }
  }
  </code></pre>
  
  <p>And my <code>webpack.config.json</code>:</p>
  
  <pre><code>const webpack = require('webpack');
  const writeFilePlugin = require('write-file-webpack-plugin');
  const { BaseHrefWebpackPlugin } = require('base-href-webpack-plugin');
  const CopyWebpackPlugin = require('copy-webpack-plugin');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
  
  const utils = require('./utils.js');
  
  module.exports = {
      entry: './src/main/webapp/app/index.js',
      output: {
          path: utils.root('build/resources/main/static/'),
          filename: 'app/[name].bundle.js',
          chunkFilename: 'app/[id].chunk.js'
      },
      cache: true,
      resolve: {
          extensions: [
              '.js', '.jsx'
          ],
          modules: ['node_modules'],
          alias: {
              App: utils.root('src/main/webapp/app/')
          }
      },
      module: {
          rules: [
              {
                  test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i,
                  loader: 'file-loader',
                  options: {
                      digest: 'hex',
                      hash: 'sha512',
                      name: 'content/[hash].[ext]'
                  }
              },
              {
                  test: /\.js$/,
                  exclude: [/node_modules/],
                  loader: 'babel-loader',
                  options: {
                      presets: ["@babel/preset-env", "@babel/preset-react"]
                  }
              },
              {
                  test: /\.css$/,
                  loader: ['style-loader', 'css-loader']
              }
          ]
      },
      plugins: [
          new BrowserSyncPlugin({
              https: true,
              host: 'localhost',
              port: 9000,
              proxy: {
                  target: `http://localhost:9060`,
                  proxyOptions: {
                      changeOrigin: false  //pass the Host header to the backend unchanged  https://github.com/Browsersync/browser-sync/issues/430
                  }
              },
              socket: {
                  clients: {
                      heartbeatTimeout: 60000
                  }
              }
          }, {
              reload: false
          }),
          new webpack.NamedModulesPlugin(),
          new webpack.HotModuleReplacementPlugin(),
          new writeFilePlugin(),
          new webpack.WatchIgnorePlugin([
              utils.root('src/test'),
          ]),
          new CopyWebpackPlugin([
              { from: './src/main/webapp/static/', to: 'content' },
              { from: './src/main/webapp/favicon.ico', to: 'favicon.ico' },
              { from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp' },
              { from: './src/main/webapp/robots.txt', to: 'robots.txt' }
          ]),
          new HtmlWebpackPlugin({
              template: './src/main/webapp/index.html',
              chunksSortMode: 'dependency',
              inject: 'body'
          }),
          new BaseHrefWebpackPlugin({ baseHref: '/' })
      ]
  };
  </code></pre>
  
  <p>But when I do a build I get the following error:</p>
  
  <pre><code>ERROR in ./src/main/webapp/app/index.js
  Module build failed (from ./node_modules/babel-loader/lib/index.js):
  SyntaxError: /.../src/main/webapp/app/index.js: Unexpected token (7:16)
  
     5 | import * as serviceWorker from 'serviceWorker';
     6 | 
  &gt;  7 | ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));
       |                 ^
     8 | 
     9 | // If you want your app to work offline and load faster, you can change
    10 | // unregister() to register() below. Note this comes with some pitfalls.
      at Parser.raise (/.../node_modules/@babel/parser/lib/index.js:6325:17)
      at Parser.unexpected (/.../node_modules/@babel/parser/lib/index.js:7642:16)
      at Parser.parseExprAtom (/.../node_modules/@babel/parser/lib/index.js:8841:20)
      at Parser.parseExprSubscripts (/.../node_modules/@babel/parser/lib/index.js:8412:23)
      at Parser.parseMaybeUnary (/.../node_modules/@babel/parser/lib/index.js:8392:21)
      at Parser.parseExprOps (/.../node_modules/@babel/parser/lib/index.js:8267:23)
      at Parser.parseMaybeConditional (/.../node_modules/@babel/parser/lib/index.js:8240:23)
      at Parser.parseMaybeAssign (/.../node_modules/@babel/parser/lib/index.js:8187:21)
      at Parser.parseExprListItem (/.../node_modules/@babel/parser/lib/index.js:9491:18)
      at Parser.parseCallExpressionArguments (/.../node_modules/@babel/parser/lib/index.js:8621:22)
      at Parser.parseSubscript (/.../node_modules/@babel/parser/lib/index.js:8514:29)
      at Parser.parseSubscripts (/.../node_modules/@babel/parser/lib/index.js:8433:19)
      at Parser.parseExprSubscripts (/.../node_modules/@babel/parser/lib/index.js:8422:17)
      at Parser.parseMaybeUnary (/.../node_modules/@babel/parser/lib/index.js:8392:21)
      at Parser.parseExprOps (/.../node_modules/@babel/parser/lib/index.js:8267:23)
      at Parser.parseMaybeConditional (/.../node_modules/@babel/parser/lib/index.js:8240:23)
      at Parser.parseMaybeAssign (/.../node_modules/@babel/parser/lib/index.js:8187:21)
      at Parser.parseExpression (/.../node_modules/@babel/parser/lib/index.js:8135:23)
      at Parser.parseStatementContent (/.../node_modules/@babel/parser/lib/index.js:9958:23)
      at Parser.parseStatement (/.../node_modules/@babel/parser/lib/index.js:9829:17)
      at Parser.parseBlockOrModuleBlockBody (/.../node_modules/@babel/parser/lib/index.js:10405:25)
      at Parser.parseBlockBody (/.../node_modules/@babel/parser/lib/index.js:10392:10)
      at Parser.parseTopLevel (/.../node_modules/@babel/parser/lib/index.js:9758:10)
      at Parser.parse (/.../node_modules/@babel/parser/lib/index.js:11270:17)
      at parse (/.../node_modules/@babel/parser/lib/index.js:11306:38)
      at parser (/.../node_modules/@babel/core/lib/transformation/normalize-file.js:170:34)
      at normalizeFile (/.../node_modules/@babel/core/lib/transformation/normalize-file.js:138:11)
      at runSync (/.../node_modules/@babel/core/lib/transformation/index.js:44:43)
      at runAsync (/.../node_modules/@babel/core/lib/transformation/index.js:35:14)
      at process.nextTick (/.../node_modules/@babel/core/lib/transform.js:34:34)
      at process._tickCallback (internal/process/next_tick.js:61:11)
  Child html-webpack-plugin for "index.html":
       1 asset
      Entrypoint undefined = index.html
      [./node_modules/html-webpack-plugin/lib/loader.js!./src/main/webapp/index.html] 1.74 KiB {0} [built]
      [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
      [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
          + 1 hidden module
  </code></pre>
  
  <p>What do I need to change in my webpack config to get this to built properly?</p>
  
  <p><strong>Edit 1:</strong> Tried to ditch the route of setting up my own webpack.config and tried to use the <a href="https://facebook.github.io/create-react-app/docs/getting-started" rel="nofollow noreferrer">CRA's</a> react scripts. But I need to specify the location of the <code>PUBLIC_URL</code> since I do not have a folder named public in the root level. So I modified my <code>package.json</code> script section to so:</p>
  
  <pre><code>"scripts": {
      ...
      "build": "set \"PUBLIC_URL=/src/main/webapp/\" &amp;&amp; react-scripts build",
      ...
    },
  </code></pre>
  
  <p>But I still end up getting the error:</p>
  
  <pre><code>Could not find a required file.
    Name: index.html
    Searched in: /.../FooApplication/public
  </code></pre>
  
  <p>How do you set CRA's public url?</p>