Customizing webpack for your own needs is a powerful functionality. It allows you full control of your app’s development and deployment process. In this article we will go over how to do that in an NX monorepo.
Table of Contents
TL;DR.
- The steps to customize the webpack config in an NX project are here.
- You can see the full solution in this repository: https://github.com/YonatanKra/nx-custom-webpack/tree/custom-webapack-config
- This PR shows the files that were changed: https://github.com/YonatanKra/nx-custom-webpack/pull/1
Webpack has been the industry standard bundler for a long time. Today you can do much more than just bundle with it. Nrwl’s NX is a monorepo management framework that sprout from the Angular CLI. It has long since became much more. You can manage all your frontend and backend projects – regardless of framework and soon even regardless of programming language. In this article, I’ll go over a less known part of Nx that was useful for me a few times in the past – customizing the webpack configuration for projects in the monorepo.
Let’s look at a project with a web app. This web app uses web components. Here’s the repository:
https://github.com/YonatanKra/nx-custom-webpack
It doesn’t really matter what the app is doing (it’s just the default app set by Nx for web components). The point is in the main file that looks like this:
A custom element is indeed created in app.element.ts
. There are two issues here though.
Problem #1: File Structure
The first is that we hard code the HTML inside the ts
file. The HTML might be more complex so we’d might want to separate the HTML from the TS file and create an app.element.html
file.
I know this issue is eligible for debate, but let’s assume we’ve decided we want separate HTML and TS files for the sake of this tutorial.
Trying to do this naively gives us this error while trying to build our app:
The solution is written in the error. We need to find a webpack loader that allows us to load HTML files the way we want to. In our case, we’d just like to get the contents of the HTML file as a string. For this, we have the raw-loader
.
We first install the raw-loader
:
yarn add -D raw-loader
And then we need to add a rule in webpack config to use this loader. Can you spot the webpack config file in the project? Spoiler – there is no such a file.
So how does one configures the webpack config with extra stuff?
How to customize webpack config for an NX project?
- Go to the workspace.json file
- Find the project you wish to edit
- In the project’s
targets.build.option
add awebpackConfig
property with a path to a config file like this:
- Do the same for the
targets.serve.options
. - Now create the config file in the designated path.
- export a function that receives a config object and a context and returns a modified config like so:This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
module.exports = (config, context) => { return { ...config, module: { ...config.module, rules: [ ...config.module.rules, { test: /\.html$/i, use: 'raw-loader', }, ], }, }; };
As shown in the code, the exported function receives the config as an input. It then modifies itsmodule.rule
property by adding theraw-loader
rule. Notice that we spread the properties we modify in order for them to be in the output and not completely overwritten. - Now you can happily compile your project with the new webpack config!
Problem #2: Shadow DOM CSS Encapsulation
The second issue is how we import the CSS. It is imported using webpack’s css-loader
. The css-loader
just takes the CSS in the file and adds it to the page. This works if we are using a simple custom element. But one of the powers of web components is the Shadow DOM, which enables CSS encapsulation.
Converting our custom element to a web component using Shadow DOM, will result in a styleless component:
Of course we’d like our app to have the style. For this, we need to inject the style into the Shadow DOM. We can use the same trick with the raw-loader
to do that:
The code in Code snippet 3 won’t work. The reason is that NX already has loaders for CSS and they clash with our raw loader. You will get the following error:
Logging the original config.module.rules
shows us this picture:
We can see in Figure 4 that the CSS rules we don’t want anymore (unless we are using a CSS compiler like SASS or LESS) are the second of a 2 members rules array. Hence, we can change our code to just use the first rule and ignore the original CSS rules:
And now our app is working!
Summary
In this article we saw how to customize the webpack configuration in a project inside an NX monorepo. The two use cases we dealt with were solved by adding a loader. In the first case we just added a loader and in the second case, we had to replace the loader for the file type.
It is very possible your application will need a more refined customization, or you’d might want to change the plugins or even the webpack’s output or optimization behavior. I hope you now have more clue on how to do it.
The default webpack configuration for my app is below & it creates a remoteEntry.js file which is used to stitch shell & the micro app:
withModuleFederation({
…moduleFederationConfig,
});
But with the configuration mentioned in the article, it is not generating the remoteEntry.js file .
How do we acheive it
What do you mean? Do you have a repository where the issue is reproduced?