Is your feature request related to a problem? Please describe.
Would like to add additional postcss plugins via the new @angular/cli v7 angular.json or custom-webpack.config.js.
Describe the solution you'd like
I would like to be able to add additional postcss plugins to the existing list that @angular/cli uses. I'm unsure if this is an undocumented or poorly understood feature, or not yet a feature. Please clarify.
Describe alternatives you've considered
@angular/cli@7+ allows a customWebpackConfig to be specified to provide custom webpack configuration, such as:
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./build/custom-webpack.config.js"
},
...
This file then technically allows you to prepend, append or replace any portion of the webpack configuration. Prior to upgrading to @[email protected] and @angular/[email protected] we had ejected the webpack configuration to make some additions. One such addition was the postcss-momentum-scrolling postcss-loader plugin that automatically enabled iOS momentum scrolling on all scrollable containers.
I am seeking support on figuring out how to generate the necessary custom webpack code to load this plugin via the supported customizations allowed by @angular/cli@7+.
Here is a sample of what I have tried in my custom-webpack.config.js file:
const postcssMomentumScrolling = require('postcss-momentum-scrolling');
module.exports = {
module: {
rules: [
{
test: /\.scss$|\.sass$/,
use: [
{
"loader": "postcss-loader",
"options": {
"plugins": [
postcssMomentumScrolling(),
]
}
}
]
},
],
},
};
As soon as I touch the scss chunk of the webpack config, it seems to do a replace instead of a merge or prepend, breaking the build.
Is there a guide or suggestions on how to see what the initial webpack configuration that @angular/cli generates that is the starting point for modifications and a way to preview/peek at the code to be executed as debugging.
Also, an example of a similar customization would be helpful.
Additional context
Also started the discussion here last week: https://stackoverflow.com/questions/53955119/how-do-i-add-an-additional-postcss-plugin-via-the-new-angular-cli-v7-angular-js
I can see here at least one problem - postcss-loader cannot be applied to sass files directly, they first should be transpiled to css.
Since the loaders are merged, simply changing your test pattern to css should add your loader into existing chain of loaders (scss -> css -> postcss).
You also may find this thread very helpful.
Thank you! I'll give it a shot. I didn't realize that .scss files got passed through all the loaders for .css files once they were transpiled.
I was working from a snippet of the ejected webpack configuration from angular 5.1.x that we had previously modified, and figured all the other loaders would have already been in there so if it could merge in the postcss plugins it might just work. The postcssPlugins variable had all the ones @angular/cli automatically added plus a few others we added... and that postcssPlugins array was used by a bunch of the loaders.
{
"test": /\.scss$|\.sass$/,
"use": [
{
"loader": "raw-loader"
},
{
"loader": "postcss-loader",
"options": {
"ident": "embedded",
"plugins": postcssPlugins,
"sourceMap": true
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": true,
"precision": 8,
"includePaths": [
"src/styles"
]
}
}
]
},
My next step after posting this discussions was debugging @angular-builders/custom-webpack/src/webpack-config-merger.js to see what the effective webpack configuration it was trying to merge into was, and did find postcss-loader in there with a list of plugins, but couldn't get the npm run build to run in the vscode debugger via launch.json so was using flatted to try to log the webpack structure to the output. Unfortunately didn't get me much further.
I did see your referenced post about tailwind.js, but didn't want to set extractCss to false unless I really had no other option.
I'll post my solution once I have it for others. Thanks for the tips!
Okay, I have a solution that seems to work to include extra postcss plugins like postcss-momentum-scrolling or postcss-rtl.
const postcssMomentumScrolling = require('postcss-momentum-scrolling');
const production = process.env.npm_config_argv.includes('--prod') || process.env.npm_config_argv.includes('production');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'raw-loader' },
{
loader: "postcss-loader",
options: {
ident: "embedded",
plugins: [
postcssMomentumScrolling(),
],
"sourceMap": production ? false : 'inline'
}
}
]
},
],
},
};
Thanks so much for the suggestion to use the /\.css$/ test @meltedspark.
Please let me know if anyone has a more graceful solution to determine whether the build is in development or production mode. This seems a bit messy:
const production = process.env.npm_config_argv.includes('--prod') || process.env.npm_config_argv.includes('production');
I should note that this custom webpack adds an additional rule to the array of rules, it does not add an additional plugin to the existing rule.
I just noticed the merge request for https://github.com/meltedspark/angular-builders/pull/152 which likely would provide a simpler way to access the development/production build environment through the build options passed in (depending on what exactly buildOptions contains).
We had used those build options in our previous webpack configuration to access the environment variables passed into npm:
module.exports = (env) => {
env = env || {};
...
return {
module: {
...
}
};
};
Yeah this pull request is waiting for UT coverage and documentation, I just didn't get to that yet. You're welcome to contribute if you want it to be merged ASAP.
Yeah this pull request is waiting for UT coverage and documentation, I just didn't get to that yet. You're welcome to contribute if you want it to be merged ASAP.
Great idea. I'll try to get to that too.
So... still struggling with properly getting the postcss additional plugins to work without breaking anything else... the above proposed solution did successfully load the postcss-momentum-scrolling npm... but in doing so it broke the paths and inclusion of fonts (and likely other assets loaded from scss files).
I also tried to mimic the exact format of the webpack module.rules configuration it is being appended to and to use that in custom-webpack.config.js but no matter what I try the fonts from node_modules do not get hashed and included in the angular dist root like they do without the customization. That results in two nearly identical chunks with different postcss plugins.
module.exports = {
module: {
rules: [
{
exclude: [`${process.cwd()}\\src\\styles.scss`],
test: /\.css$/,
use:
[{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options:
{
ident: 'embedded',
plugins: [
postcssMomentumScrolling(),
],
"sourceMap": production ? false : 'inline'
}
}]
},
{
include: [`${process.cwd()}\\src\\styles.scss`],
test: /\.css$/,
use: [
'style-loader',
`${process.cwd()}\\node_modules\\@angular-devkit\\build-angular\\src\\angular-cli-files\\plugins\\raw-css-loader.js`,
{
loader: "postcss-loader",
options: {
ident: "embedded",
plugins: [
postcssMomentumScrolling(),
],
"sourceMap": production ? false : 'inline'
}
}
]
},
],
},
};
I'll create minimal repository to reproduce the issue for some assistance debugging.
I also debated editing @angular-builders/custom-webpack/src/webpack-config-merger.js so that it will automatically merge plugins where the test/include/exclude/loaders are all the same... but not sure if that is the correct direction.
I'm guessing my understanding of how webpack loaders is lacking or I'm missing something relatively simple.
Let's try another direction. Leave your test as scss but change the merge strategy for loaders to prepend ('module.rules': 'prepend').
This theoretically should put your loader at the beginning of the rules array. Loaders are executed from right to left. So technically your loader will be the last loader applied.
Again, I don't remember exactly what are the regex tests they use inside Angular CLI so it might work in a different way.
Anyways, it would be very useful if you added here the resulting configuration you get (I understand that you managed to change the sources in order to print this configuration out).
Also, this is used for merging so it might help you in understanding how the loaders are merged.
Regarding your production approach - the right thing to do (until the pull request is merged) is to keep two different webpack configs and use configurations option in _angular.json_ to specify the right one for the appropriate environment.
One more question. Are you trying to build in production mode or development? Because if it's production then it completely does make sense that it won't work without the extractCss=false. For the exact same reason it won't work in tailwind.js thread. Although it might work with the prepend thing but I didn't try.
Thank you! The tip to do it with scss, and what I learned while debugging was what I needed. It is working now, I'm just isolating the minimum code required to add the postcss plugins. I will post the solution here once I have it. Its not overly fast to test as each minor change requires a build (since live doesn't pickup these changes dynamically)... and our code base takes 50+ seconds each build. Hopefully I'll wrap it in the next few days.
Assuming I can post one more message on a closed issue, feel free to close this issue as its obviously not a problem with angular-builders, but an issue with lack of understanding and relevant examples. I'll add one more post with the final code for reference by others when I refine it, and see if I can get the docs and UT written for that related environment configuration pull request (https://github.com/meltedspark/angular-builders/pull/152).
Sounds great, looking forward to seeing this! Thanks!
@michaelcm Hey, any update on the final example? Also, are you still willing to add UT and docs to the pull request or should I take it?
Sorry, I got moved to another project for the last few weeks. I would expect to get back to the final testing of this next week. I'm still willing if time permits. We are moving out of our house this weekend too, so going to be a busy few weeks.
One more question. Are you trying to build in production mode or development? Because if it's
productionthen it completely does make sense that it won't work without theextractCss=false. For the exact same reason it won't work intailwind.jsthread.
Thank you, setting "extractCss": false is what made my production build work with postcss (& aot set to true). My custom webpack:
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
enforce: "pre",
loader: 'import-glob-loader'
},
{
test: /\.scss$/,
use: [
{ loader: 'postcss-loader' },
'sass-loader'
]
}
]
}
};
What _is_ the reason that works, by the way?
@michaelcm Any chance you could post the working config? I'm trying to get the same thing running, PostCSS plugins in an Angular CLI 7 app, and not having any luck so far.
Yes, back on this project now. Will get the example up here as soon as I confirm its the final working code.
Still interested in the final solution @michaelcm. :-) Broke my head over trying to solve this for a similar implementation, and enforce: 'pre' was the required option for me to get it working. Thanks @adrexia! As this is the only spot where I read about enforce: 'pre' being part of the proposed solution. While I was looking into getting the prepend merge strategy to work, adding a merge strategy was not required for getting rid of the errors.
Most helpful comment
Let's try another direction. Leave your test as
scssbut change the merge strategy for loaders toprepend('module.rules': 'prepend').This theoretically should put your loader at the beginning of the rules array. Loaders are executed from right to left. So technically your loader will be the last loader applied.
Again, I don't remember exactly what are the regex tests they use inside Angular CLI so it might work in a different way.
Anyways, it would be very useful if you added here the resulting configuration you get (I understand that you managed to change the sources in order to print this configuration out).
Also, this is used for merging so it might help you in understanding how the loaders are merged.
Regarding your
productionapproach - the right thing to do (until the pull request is merged) is to keep two different webpack configs and useconfigurationsoption in _angular.json_ to specify the right one for the appropriate environment.One more question. Are you trying to build in production mode or development? Because if it's
productionthen it completely does make sense that it won't work without theextractCss=false. For the exact same reason it won't work intailwind.jsthread. Although it might work with theprependthing but I didn't try.