The FDK comes built-in with Webpack 5 and a Webpack configuration file to mount during the compilation and the build phases, whenever the FDK detects the project is developed with React or Vue, the project is compiled using the Webpack with default Webpack configuration.

Though the FDK has a default Webpack configuration for the supported Single Page Apps, It is possible to provide custom configurations and this tutorial will help you guide through that.

Prerequisites

What we'll build today?

In this tutorial we will override the default webpack configuration in the FDK by providing custom webpack config.

By default the webpack is configured to build the assets and place it inside app/scripts, in this tutorial we will create a custom config to place the built assets in a differnt folder.

The code snippet shown below is the default webpack configuration that comes with the FDK, you can choose to make whatever changes you wish to the configuration, but make sure you follow the guidelines given below

  1. The output should always point to or be inside the app directory, so the app can be packed properly during fdk pack
  2. If you use any new dependencies in the configuration, make sure you install the dependencies inside the project root.
  3. Prefix the paths with ${process.cwd() so the FDK can locate the files inside your app folder
'use strict';

const HtmlWebPackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');


module.exports = {
  entry: {
    main: ['@babel/polyfill', `${process.cwd()}/src/index.js`]
  },
  output: {
    globalObject: 'this',
    path: `${process.cwd()}/app/scripts`,
    filename: '[name].[contenthash:8].js',
    chunkFilename: '[name].[contenthash:8].js',
    publicPath: './scripts'
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx|test.js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(css|scss)$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name][contenthash:8].[ext]',
              outputPath: '/assets/img',
              esModule: false
            }
          }
        ]
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader'
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin({
      dangerouslyAllowCleanPatternsOutsideProject: true,
      dry: false
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:8].css',
      chunkFilename: '[name].[contenthash:8].css'
    }),
    new HtmlWebPackPlugin({
      template: `${process.cwd()}/public/index.html`,
      filename: `${process.cwd()}/app/index.html`
    })
  ],
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: -10,
          chunks: 'all'
        }
      }
    }
  }
};

In the next section, we will create a custom config to override the the default config.

you can define the custom webpack configuration by providing a path to the configuration file on the package.json file of the app.

The path to the configuration file should be provided in the configPath of the fdkConfig in package.json, like shown in the example below.

package.json

{
  "name": "react-webpack-dev",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "fdkConfig":{
    "frontendFramework": "react", 
    "configPath": "webpack-config/webpack.config.js" // path to Your Custom Webpack config, under /webpack-config folder
  },
  "devDependencies": {
    "@babel/plugin-transform-spread": "^7.13.0",
    "@testing-library/jest-dom": "^5.11.6",
    "html-loader": "^1.3.2",
    "jest": "^26.6.3",
    "jest-css-modules": "^2.1.0"
  },
  "dependencies": {
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.0"
  },
  "scripts": {
    "test": "jest test --coverage",
    "code-sanity": ""
  },
  "jest": {
    "roots": [
      "./app/src"
    ]
  }
}

Now that we have enabled the custom config in the app.js, We shall start writing a custom config to place the built javascript assets inside js folder instead of the default scripts folder

'use strict';

const HtmlWebPackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');


module.exports = {
  entry: {
    main: ['@babel/polyfill', `${process.cwd()}/src/index.js`]
  },
  output: {
    globalObject: 'this',
    path: `${process.cwd()}/app/scripts`,
    filename: '[name].[contenthash:8].js',
    chunkFilename: '[name].[contenthash:8].js',
    publicPath: './js'
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx|test.js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(css|scss)$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name][contenthash:8].[ext]',
              outputPath: '/assets/images',
              esModule: false
            }
          }
        ]
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader'
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin({
      dangerouslyAllowCleanPatternsOutsideProject: true,
      dry: false
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:8].css',
      chunkFilename: '[name].[contenthash:8].css'
    }),
    new HtmlWebPackPlugin({
      template: `${process.cwd()}/public/index.html`,
      filename: `${process.cwd()}/app/index.html`
    })
  ],
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: -10,
          chunks: 'all'
        }
      }
    }
  }
};

Once the configurtion is completed, run the app using fdk run, you can see that the built assets are placed inside the app/js folder.

In this Tutorial we learned about,

✅ How to write custom webpack configs for single page applications.

What's next?

Once the tutorial is completed, you can expand the horizon by writing advanced Webpack configs like minimizing assets, Tree shaking, and all the other customizations supported by Webpack.