1

So I have a Spring boot and Java based REST API project that required a React frontend. So I used create-react-app to generate a simple react project that I could import. Here's the project folder structure:

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

Here's my package.json:

{
  "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 && 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": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

And my webpack.config.json:

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: '/' })
    ]
};

But when I do a build I get the following error:

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 | 
>  7 | ReactDOM.render(<App />, 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

What do I need to change in my webpack config to get this to built properly?

Edit 1: Tried to ditch the route of setting up my own webpack.config and tried to use the CRA's react scripts. But I need to specify the location of the PUBLIC_URL since I do not have a folder named public in the root level. So I modified my package.json script section to so:

"scripts": {
    ...
    "build": "set \"PUBLIC_URL=/src/main/webapp/\" && react-scripts build",
    ...
  },

But I still end up getting the error:

Could not find a required file.
  Name: index.html
  Searched in: /.../FooApplication/public

How do you set CRA's public url?

1
  • Your package.json and webpack config seem to be overly complicated for a fresh project. I've never used CRA yet, but if you're attaching it to Spring Boot, maybe it isn't as suitable, in contrast to a node app. Have you tried doing just doing your own minimal React config? You can even get it integrated into Gradle. I've just learned about it myself and wrote a post on how to do it: andrew-flower.com/blog/Spring-Boot-and-React-1 Commented Jul 30, 2019 at 12:09

1 Answer 1

1

To set the public location, I believe you can setup the PUBLIC_URL using a .env file in the root of your project, setting that variable.

PUBLIC_URL=/src/main/webapp/

Then the build should find it.

See also:

https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables https://facebook.github.io/create-react-app/docs/using-the-public-folder

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.