New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
why async? #68
Comments
@stevenvachon postcss is used only asynchronously. Sync mode exists only for debug. Also you get this warning cause one of the plugins is async and couldn't be used synchronously. |
Ok, thanks! |
@TrySound is there a specific reason to not support the sync API of PostCSS? I'm currently working on an own plugin (postcss-extract-media-query) where I'm forced to do synchronous calls (because my extraction is not part of the bundler flow). My solution is using csswring which works without problem. But I'd prefer to use cssnano as it is more supported. |
/cc @evilebottnawi |
@SassNinja some packages what we use in |
If I remember correctly we added async just for postcss-svg. Maybe there is a option to keep sync API. |
Anyway right now we freeze new feature(s), let's open this and maybe do this in |
What does it mean? You can do async js everywhere. If you don't use require extensions hook I don't see any reason for sync api and make things more complex and slower. |
Ok got it, one/some packages are the wrongdoer. But if @ai is right and it can be fixed in future version, it would be awesome!
@TrySound I'm afraid that's not possible in my case (would be happy if I'm wrong). If I do this async I'll take the risk of race conditions (webpack thinks postcss is done and continues while the plugin might still be running). |
@SassNinja Some notes for webpack
Related webpack-contrib/postcss-loader#354? About code:
|
You mix logic postcss and webpack, it is very bad practice, just write postcss plugin what get one css file and output two/three/more based on count of media queries. When ping me and I'll show you how it is use in |
@evilebottnawi thanks for the feedback! I've (again) some questions :)
You're talking about the webpack compiler? Do you have a link to the appropiate section in the docs? I can't find anything about
I assume you're refering to webpack-contrib/postcss-loader#354 but as I understand the feature ( But talking about webpack: although I've built the plugin primary for weback it can (in theory - tests running) be used with other bundlers as well. I'm afraid that too much webpack dependency (compiler, postcss-loader) won't offer that much more benefits... or do you think it would be better nevertheless?
Do you literally mean a Map object? (I don't know the advantage in this case bcz a regular object suits quite well) Or are you just talking about renaming the option?
My plugin does not only extract the media query, but also merge equal rules into one.
I first thought exactly the same. But the problem is I'm writing the extracted files within my plugin ( It's simply a problem here I'm not emiting the files with webpack. On the other hand I'd like to keep my plugin bundler independent (see above)...
Thanks for the tip! I'll check this when I've got some time. But in the end it's only about a few
So perfect way in your eyes would be to send the CSS ( Even if possible (still not sure how to do - see questions above) this would mean 100% webpack dependency, wouldn't it? |
const postcss = require('postcss')
const plugin = postcss.plugin('plugin-name', (options) => {
return (css, result) => {
const queries = []
css.walkAtRules((rule) => {
/* ...extract @media */
queries.push({
type: 'file',
name: 'tablet',
value: ...css
})
})
result.messages = result.messages.concat(queries)
}
})
module.exports = plugin const postcss = require('postcss')
class CSSMediaQueryPlugin {
constructor (options = {}) {
this.plugin = { name: 'CSSMediaQueryPlugin' }
this.options = options
}
apply (compiler) {
const { plugin, options } = this
const { compilation } = compiler.hooks
compilation.tap(plugin, (compilation) => {
const { assets } = compilation
const { optimizeAssets } = compilation.hooks
optimizeAssets.tapAsync(plugin, (assets, cb) => {
Object.keys(assets)
.filter((asset) => asset.endsWith('.css'))
.forEach(async (asset) => {
const src = assets[asset]
options = Object.assign(options, { from: asset })
const { css, messages } = await postcss([ /* your plugin */ ])
.process(src, options)
messages
.filter((msg) => msg.type === 'file')
.map(({ name, value }) => {
const name = asset.replace(/\.css$/, `-${name}.css`)
compilation.assets[name] = value
})
// if only the queries get pruned from the original
compilation.assets[asset] = css
// if all css gets split up into chunks
delete compilation.assets[asset]
})
cb()
})
})
}
}
module.exports = CSSMediaQueryPlugin
Code is obviously pseudo, untested and needs some polishing based on what you want in the end... |
@michael-ciniawsky many thanks for your code example – looks quite good! Before having noticed it I did experiment with a custom webpack-loader solution but have finally given up that idea because it's always limit to the one chunk. No matter what I add to the code ( Afterwards I started to work on a plugin solution. Is there any advantage of using the compilation optimizeAssets hook? Anyway I'll try to create a working plugin based on your and my code. The compiled CSS has one sourceMap ( Do you have an idea how to fix the sourceMap issue? |
I've created a repo with first draft: I haven't found a solution for the sourceMap issue yet. any help appreciated |
Can this be closed? |
@andyjansson i think yes, some optimization impossible do sync |
So it isn't possible to use cssnano synchronously, right? |
Why you need cssnano in sync mode? |
We can implement this in next version(s), i will ping you |
@evilebottnawi: Correct, |
I too have a use-case that would really benefit from cssnano being available in sync mode. It would allow us to transition over from CleanCSS. |
Just encountered another issue with |
It is possible to use the current version of import postcss from 'postcss';
import cssnanoPresetDefault from 'cssnano-preset-default';
const preset = cssnanoPresetDefault();
const asyncPlugins = ['postcss-svgo'];
const plugins = preset.plugins
.map(([creator, pluginConfig]) => {
// replicate the `initializePlugin` behavior from https://github.com/cssnano/cssnano/blob/a566cc5/packages/cssnano/src/index.js#L8
return creator(pluginConfig);
})
.filter((plugin) => {
return !asyncPlugins.includes(plugin.postcssPlugin);
});
const result = postcss(plugins).process(css).toString(); |
With |
thanks @10xjs it worked! for those interested i'm using this in a typescript transformer which doesn't currently have an async api (...that i've seen 😅) |
As I see it, the issue is that the cssnano does not implement the |
I think we can close this issue as the cssnano plugins are sync, it's PostCSS itself that as of PostCSS 8 does not have an (offical) sync API any more. |
PostCSS 8 still have sync API (most of my plugins are sync). |
Is it officialy supported? The docs still say 'this method is only for debug purpose' https://postcss.org/api/#lazyresult-css |
This recommendation is for runner’s developers (like Plugins still can use sync or async APIs depends on internal needs. If you have a wrapper around the single plugin (so you sure that it is sync plugin), you can call Maybe I should add this note about wrappers also to docs. |
I fixed docs postcss/postcss@7cccfac |
@ai Does the latest version of cssnano support the synchronization API? |
@kiner-tang I am not cssnano maintainer |
@kiner-tang I am not sure I understand the question. What are you trying to do? |
@10xjs I tried your method and got const isPlugin = (x: PostCSSPlugin|PostCSSProcessor): x is PostCSSPlugin => 'postcssPlugin' in x;
const cssnanoPreset = cssnanoPresetDefault();
const asyncPlugins = [
'postcss-svgo',
'css-declaration-sorter',
];
const cssnanoSyncPlugins = cssnanoPreset.plugins
// replicate the `initializePlugin` behavior from https://github.com/cssnano/cssnano/blob/a566cc5/packages/cssnano/src/index.js#L8
.map(([creator, pluginConfig]) => creator(pluginConfig))
.filter(plugin => !isPlugin(plugin) || !asyncPlugins.includes(plugin.postcssPlugin)); |
I'd much prefer to use postcss synchronously in my current project.
The text was updated successfully, but these errors were encountered: