Customize Webpack configuration

Description

We want to allow users to extend the Webpack configuration.

User Stories

As a Frontity developer
I want to customize the default Webpack configuration
so that I can use change the default configuration and add additional features

Possible solution

Use the frontity.config.js file where you can export a function that receives the current Webpack config object.

In Frotity, we have 3 different configs, one for the server, another for the es5 bundles and another for the es6 (“module”) bundles.

This function will be run 3 times, one for each target.

export const webpack = ({ config, mode, target }) => {
  // Change the publicPath.
  config.output.publicPath = "https://mycdn.com/";

  // Add support for a new file type.
  config.modules.rules.push({
    test: /\.ext$/,
    loader: "some-loader"
  });

  // Change devtool option for development mode.
  if (mode === "development") {
    config.devtool = "cheap-eval-source-map";
  }

  // Add an alias for the server.
  if (target === "server") {
    config.resolve.alias["some-package"] = "other-package";
  }

  // Add an external for the client (both es5 and module).
  if (target === "es5" || target === "module") {
    config.externals["some-package"] = "window.variable";
  }
};

We should allow for frontity.config.js files in:

  • The root folder of the project: People can add configuration specific to their project.
  • Inside packages: Package developers can add configuration specific to their packages.

@mmczaplinski opened another FD but Babel configuration instead of Babel: Customize Babel configuration

Babel and Webpack configuration are generated exactly in the same way, so we should be able to add both features at the same time.

Let’s keep the conversation in this one.

3 posts were split to a new topic: Support for mp4 videos

I’ve read that Webpack has relative path aliasing baked in. My workflow breaks from the mars-theme example and nests files pretty deep and this is definitely something that could save a lot of headache.

resolve: {
  alias: {
     '@common': path.resolve(__dirname, ‘src/components/common/’),
     '@images': path.resolve(__dirname, ‘src/assets/images/’)
  }
}
1 Like

@mhigley,

I found to make Frontity support the module aliases, was by digging into the webpack-config of Frontity and making the change there (node_modules/@frontity/core/dist/src/config/webpack/resolve.js).

In order to automate this, I have added a postinstall-script to the package.json which manipulates this file.

scripts{
    ...,
    "postinstall": "node scripts/extend-frontity-aliases.js"
}

I created a file “scripts/extend-frontity-aliases.js”

// Make alias work for frontity
const fs = require("fs");
const path = require("path");

const alias = `Components: "${path.resolve(
  __dirname,
  "../packages/mars-theme/src/components"
)}",`;

const utils = `Utils: "${path.resolve(
  __dirname,
  "../packages/mars-theme/src/utils"
)}",`;

const sampledata = `SampleData: "${path.resolve(__dirname, "../sampledata")}",`;

// Read the original file
const originalResolveJS = fs.readFileSync(
  "node_modules/@frontity/core/dist/src/config/webpack/resolve.js",
  "utf-8"
);

// Insert alias line
const lines = originalResolveJS.split("\n");
const index = lines.findIndex(line => line.includes("alias: {"));
lines.splice(index + 1, 0, alias);
lines.splice(index + 1, 0, utils);
lines.splice(index + 1, 0, sampledata);

// Write back modified file
fs.writeFileSync(
  "node_modules/@frontity/core/dist/src/config/webpack/resolve.js",
  lines.join("\n")
);

:warning: This is a pretty extreme hack and I would not recommend moving forward with these custom aliases until Frontity supports e.g. extending its webpack config.

1 Like

Hey guys :slightly_smiling_face:

Yes, we are going to support customizing Webpack via a frontity.config.js file, but that may still take a while.

Regarding alias, my personal recommendation is to avoid them. We’ve used them in the past but they generate more problems than benefits when you need to import the code in someplace different, like for example unit testing the code or publishing the code in npm.

1 Like

4 posts were split to a new topic: How to use Emotion Theming

4 posts were split to a new topic: Vercel and webp images

2 posts were merged into an existing topic: Integrating ThreeJS on Frontity

Maybe time to switch to https://github.com/evanw/esbuild 100x faster.

I’m working on something that requires customizing the webpack config and adding a new entry point.

I’ve started looking into this, however the way frontity imports packages and settings is still not quite clear to me, is there a good place to start looking at? I have followed the code that merges the config and imports the main frontity.settings.ts but I’m missing some of the magic: i.e when and where frontity imports packages and its settings. Any FD or PR that you guys can point me to would be greatly appreciated.

I can show you that in a call if you want, and then we can publish the video here so it is helpful for the Feature Discussion itself.

What do you think?

Sure, that would be great!

Awesome. I’ll send you a message :slightly_smiling_face:

This is the meeting we had, with a summary of how the dev and build scripts generate the client and server bundles, and with an special emphasis on the Webpack configuration and how we thought packages should be able to extend that configuration.

It also has an explanation of a changes we plan to do: Instead of generating the all the client bundles for all the sites in a single Webpack run, use a single Webpack run for each site.

These are the drawings: Excalidraw | Hand-drawn look & feel • Collaborative • Secure

1 Like

@nicholasio.oliveira: could you please add a small explanation about the use case of Webpack extensibility that you need? Thanks! :slightly_smiling_face:

Hi there,

I need to add this to the webpack file

module: {
  rules: [
    {
      exclude: [/node_modules\/(?!(swiper|dom7)\/).*/, /\.test\.js(x)?$/],
      test: /\.js(x)?$/,
      use: [{ loader: 'babel-loader' }],
    }
  ],
}

Could you please point me to the right direction?

Thanks,
Jeff

Hey @jeffceirello :wave:

This is the webpack file that contains the module definition: frontity/modules.ts at dev · frontity/frontity · GitHub

You can patch it using patch-package - npm if you want.

I’ve started looking into this and recorded a small video to get some early feedback.

1 Like

I love it! :heart::grinning_face_with_smiling_eyes:

My only feedback would be to use a named export in the frontity.config.js file, to be able to add more stuff in the future:

// frontity.config.js
export const webpack = ({ ... }) => ...

Other than that, it looks great!

By the way, we also had a FD to customize babel configuration (Customize Babel configuration). But maybe we can close that for now, because configuring Babel will be possible using this:

// frontity.config.js
export const webpack = ({ config }) => {
  const babel = config.module.rules.find(
    (rule) => rule.use.loader === "babel-loader"
  ).options;

  // Add a new plugin.
  babel.plugins.push("my-own-babel-plugin");
};

The other option would be to get the frontity.config files at this point: frontity/index.ts at dev · frontity/frontity · GitHub and run the babel config through an babel exports of the frontity.config.js files:

// frontity.config.js
export const babel = ({ config }) => {
  // Add a new plugin.
  config.plugins.push("my-own-babel-plugin");
};

Then, pass the babel config to getWebpack() and run the webpack config through the webpack exports of the frontity.config.js files.

What do you think?