Use Postcss in Custom Angular Library

Hi @jeb , nice to see you again too.

Sure, I will explain to you why.
I am working in an Angular Project that is deployed as a web component. That web component is used/embedded in thirds party web sites.

Some thirds party website uses css global selectors in a bad way causing overriding in our web component.
One way we see to prevent the css overriding that work for us is using CSS Modules.

Also, when there are multiples CSS rules for the same element we know that it will win the rule with more specific selectors. Because of that, we can use the postcss-prefix-selector in order to make our class name value has more specific selectors.

Example:

Before Deploy 1:

<div class="grid-container">
</div>

After Deploy 1:

<div class="german-prefix grid-container">
</div>

Additionally, we can hash it in order to prevent having a conflict with other CSS rule of an external site:

<div class="_2q1pPTls NF9ou4CX">
</div>

Finally, we can add a different prefix selector every time we make a new deployment and then hash the class name + the prefix, in order can prevent (or at least make it more difficult) the web component be automated by external software.

About ViewEncapsulation it wasn’t enough to prevent CSS overriding.

On resume, the web component is already Obfuscated thanks to CSS Modules. However, the web component is a custom library of components that we would like to implement CSS Modules in order to prevent CSS overrides.

An example, is that a form that should seem like this:

In a third party web site is view like this because of css overriding:

(Sorry I added the second image in other response, but the system only allows me to upload one image for response).

Other solution that I thought, it’s make all the styles of the Angular library global, in order to use scss-bundle + postcss-modules to hash them all, like it I did in the response of my own question :sweat_smile: :

However, but I can figure out yet, is how to replace the class names in the HTML’s files. I thought perhaps using lodash like I did before to change the values in the ngClass but instead of applying to only the ngCass doing for all the class names. But. I didn’t figure out how to modify the HTML’s files during or after the build.

@gquinteros93 I can feel your pain but this is exactly what ViewEncapsulation is designed for - to encapsulate components from each other and global styles.
Essentially adding a hash to class names is exactly what Angular Compiler does under the hood. I wonder why it wasn’t enough for you. Could you please elaborate more on that?

1 Like

Hi @jeb , thanks for your response.

Yes, I use ViewEncapsulation on my components, however it’s not enough to prevent the css overrides.

The issue is that some third party websites use class names as selector to set css rules.
I want to prevent that through hashing my classes names. Because of that, I need to use postcss-modules and posthtml-css-modules.

As the images of the form I showed you before, the ViewEncapsulation wasn’t enough to prevent the third party website add a gray frame to my inputs in the contact form.

@gquinteros93 Got you. Have you tried ViewEncapsulation.ShadowDom? It might give you what you want.

1 Like

Keep in might though it’s not available in all the browsers (had to post it as a separate comments since I’m a new user and not allowed more than 2 links in the post :man_facepalming:)

hi @jeb

Yes, ViewEncapsulation.ShadowDom was an option that we handle.

But, like you said it’s not available for all the Browser, because of that I used the CSS modules approach.

My mistake/error was thinking that I would be able to extend the Angular Library build like I did in the Angular Project. I didn’t know that ng-packagr is not able to extend.

There is a discussion to extend/modify template and styles compilation in ng-packagr :

But, the PR is still open and they didn’t merge it yet.

Good afternoon, @m.koretskyi, @LayZee and @jeb.

Did you have the opportunity to see if there is a possible solution to modify the scss and html files during the compilation of an angular library?

In my case, I researched and I find a possible solution that are developing in ng-packagr:


It seems to be ready, however, they have a pull request open from Mar 5, 2018 and they didn’t merge it yet.

Thanks in advance for your time and effort.

Regards,
German.

Could it help you to use ng-packagr API in a script? See comment by Alan Agius:

Hi @LayZee ,

Yes, that’s is a good option.
In fact, I am already using scss-bundle in the postbuild to export the scss files of my library.

However, what I could not achieve yet is how to replace the class name in the html by the hash name during or after the build.

Because, after the build the html code are embedded in the js files of the library.

Perhaps, I can use the same approach I used to replace the class name with Ngclass through Lodash.

But, I don’t know how to do that in the html code that are embedded in the js files of the library.

Do you have any idea how to do that?

The other option (that I also do not how to do it) is modifies the HTML files during the compilation before they get embedded in the js files. Because, later I can modify the scss files with scss-bundle like you said before.

Unfortunately, I don’t know how to help you with what you’re asking. I only now realized that ng-packagr doesn’t use Webpack.

I also noticed that the document you’re referring to now says that developers won’t be able to extend the Rollup configuration:

Hi @LayZee, thanks for your response.

Yes, extending rollup was my first idea. But, now I see it’s not possible. Also, from what I researched they only use rollup to do the umd bundle, so now I think extending rollup was not the best solution.

If I just were able to modify the HTML files during build time (or after) I would use Lodash and replace the class names by the hashed class names like I did in the Angular Project for ngClass but for all the class names:

Perhaps @m.koretskyi or @jeb can have an idea to do that :pray:

Finally, I want to thanks you all you guys (@LayZee, @m.koretskyi and @jeb) for giving me support and helping me with this challenge, I know you are spending your free time trying to help me resolve this crazy idea.

I’ve asked Serkan Sepahi to take a look. He’s a tooling and compiler nerd and I mean that in the best way possible :smile:

1 Like

Great :raised_hands: , I hope he can help us.
I will cross my fingers :crossed_fingers: .
Thanks for you help :muscle:

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Ok, I feel like I have to go a bit deeper.

Here is the thing: ng-packagr has a completely custom build chain. The chain is based on transforms and pipelines (read more here).
This architecture is extensible to some degree however it’s nearly impossible to do what you want. If the STYLESHEET_TRANSFORM was implemented it would have been a easier but unfortunately it’s not implemented, despite being mentioned in one of the examples.

Let’s start with your first idea - rollup. rollup is used by ng-packagr solely for bundling purposes, it doesn’t take any part in compilation and file processing. rollup is applied inside WRITE_BUNDLES transform, which is implemented, and it even has an option for custom plugin. Since WRITE_BUNDLES is an existing transform, theoretically it could be replaced with a custom provider. However, rollup is applied deep inside this transform so you would have to basically copy-paste the entire transform tree down to the rollup function in order to be able to add your custom plugin. Which, obviously, can break with every minor release. But even when you did that it wouldn’t solve your problem entirely. rollup is processing only fesm and umd bundles and in library build you also have esm modules which are not processed by rollup.

Let’s face it - you cannot modify rollup process in order to change the final bundle.

Your another option is to try replacing the compileNgcTransform with a custom one which mimics its behavior but passes to compileSourceFiles function a custom stylesheetProcessor, which, in turn, is the same processor as the default but applies additional postcss plugin.
This can be easily broken by a minor release too (since you copy-pasted the whole build pipeline) and it’s also hardly maintainable.
Moreover, if you managed to replace the whole pipeline and applied your post css plugin you still have to modify the html. Which you can’t do inside the build process, because HTML and TS processing is done by ng compiler host and there is no way to hook into it. You’ll have to override the compiler host, and believe me, you don’t want it.
So you’ll still have to go to the final bundle/modules and somehow replace the class names with hashes that are written during the build process to a json file.

As you can see there is almost no way to do what you want with ng-packagr.
In my opinion your best shot is to try modifying the final bundles/modules with a custom post-build script.

2 Likes

Hi @jeb,

Thanks a lot for your explanation. It was really complete and you explained all possible cases and why they are not achievable.

I will make the styles of the library global and hash all the syles with scss-bundles and postcss-modules. Then, I will implement the post-build script to modify HTML code in the bundles on the dist folder.

I will copy my solution here in order to share it with you and the community.

That seems to be the only solution available until the ng-packagr add the features of:

  • STYLESHEET_TRANSFORM
  • TEMPLATE_TRANSFOR
1 Like

Hi guys, how are you?

I have just wanted to let you know I was was able to use css modules in a custom library modifying the final bundles/modules like @jeb suggested :clap: .

Later I will do another reply explaining the approach I used and copying the scripts I used.

Thanks for your help and support.

1 Like

That would be really interesting to see. Glad it worked out for you!