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
Document how to declare a PostCSS plugin in an ES6/TypeScript module #1771
Comments
let plugin = () => { … }
plugin.postcss = true
export default postcss Where do you think we should change docs? |
That was the first thing I tried, but it doesn't work if you're loading it from TypeScript:
I also tried const plugin: PluginCreator = (opts: Options = {}): Plugin => { … };
plugin.postcss = true;
export = plugin; but this produced
So far, this is the best I've been able to manage: const plugin: PluginCreator = (opts: Options = {}): Plugin => { … };
export = plugin; ...but this doesn't include the |
It's worth noting that the $ npx postcss-cli -u ../../build/index.js < test.css
> postcss-src@1.0.0 compile
> tsc -p .
Plugin Error (../../build/index.js): TypeError: (intermediate value).default is not a function' |
Okay, I've found an incantation that works: // eslint-disable-next-line @typescript-eslint/no-namespace
namespace plugin {
export interface Options { … }
}
const plugin: PluginCreator<olugin.Options> = (opts = {}) => { … };
plugin.postcss = true;
export = plugin; It would be nice if there were an alternative way to declare these plugins that was more module-system friendly—allowing the |
These problems are coming from ESM support in TS.
|
Sure, no argument there, but that's not really something we can avoid at least until native ESM is widely used everywhere.
This just exports a value with the name
If I do that I'll prevent anyone but other ESM users from using my plugin. |
There is no way to have dual CJS/ESM package solution which will work in 100% cases and use |
I would happily use named exports—but I'm also trying to make an idiomatic PostCSS plugin 😅. That's why I'm asking for PostCSS to accept a plugin that uses named exports. |
I think it is better to use CJS for plugins rather adding named export to JSON config loading. I have no idea about good API for named export. But you can use named export in JS format of config. |
But, as discussed, the CJS plugin format is difficult and messy to use correctly with TypeScript.
What about this: if a module defines a member named
When I'm writing a PostCSS plugin, only having it work for users who load plugins with JS and not for users who load plugins via JSON or |
Also the same import { postcss as postcssNested } from 'postcss-nested` I rather prefer to wait a little when TS will fix ESM support (will avoid dirty hacks). |
Are you sure TypeScript is ever going to fix this? Do they even think of this as a bug? My understanding from reading through documentation around this is that ESM's |
I am dreaming about the future when TS of |
That's not some far-off future; I can do that today by setting The issue here isn't that TypeScript decided to do something weird and idiosyncratic with ES6 syntax; the issue is that the incompatibility between CJS and native-ES6 forces users to transpile until there's a critical mass of ES6 authors out there that it's viable to ship packages that only work for them. The good news is that you can make that world a little bit closer by making it easier to use transpiled-ES6 with PostCSS. If you don't want to support a top-level |
Hm. Cool idea. I will look how to implement it. |
I am no expert on ESM or CJS but have been following this thread and the pull request because I want to handle this correctly for all plugins we author from https://github.com/csstools/postcss-plugins For some time we have been using conditional exports and rollup. We also have some tests for these :
We don't currently have tests for Typescript, but I've manually verified this and seems to work. Same for passing plugin options. Afaik these are true:
Are we affected by this issue but not aware? As stated above I am no expert, so the steps I take to verify that it works are limited by my knowledge of ESM and CJS. |
@romainmenke It looks like the CJS blob you're distributing is set up not to cause CJS users problems. That does raise the question, though: why even bother distributing ESM, when ESM users could just as easily import your CJS blob? |
That was from before my time as a maintainer of these plugins so I would have to start digging through old commits. Most likely this happened :
I don't dare removing it now :) |
Hi @nex3, I have just read the thread, and maybe you already solved your issue since then but perhaps I can apport my two cents here. I would not recommend a named export, there are many tools/frameworks in which you need to specify the If you are still dealing with that, try a setup similar to the one that I created in Regards |
Configure project to use ES6 modules to enable top-level await capabilities. This change helps project to align well with modern JS standards. - Set `type` to `module` in `package.json`. - Use import/export syntax in Cypress configuration files. - Rename configurations files that do not support modules to use the `.cjs` extension: - `vue.config.js` to `vue.config.cjs` (vuejs/vue-cli#4477). - `babel.config.js` to `babel.config.cjs (babel/babel-loader#894) - `.eslintrc.js` to `.eslintrc.cjs` (eslint/eslint#13440, eslint/eslint#14137) - `postcss.config.js` to `postcss.config.cjs` (postcss/postcss#1771)
Configure project to use ES6 modules to enable top-level await capabilities. This change helps project to align well with modern JS standards. - Set `type` to `module` in `package.json`. - Use import/export syntax in Cypress configuration files. - Rename configurations files that do not support modules to use the `.cjs` extension: - `vue.config.js` to `vue.config.cjs` (vuejs/vue-cli#4477). - `babel.config.js` to `babel.config.cjs (babel/babel-loader#894) - `.eslintrc.js` to `.eslintrc.cjs` (eslint/eslint#13440, eslint/eslint#14137) - `postcss.config.js` to `postcss.config.cjs` (postcss/postcss#1771) - Provide a workaround for Vue CLI & Mocha ES6 modules conflict in Vue configuration file (vuejs#7417).
Configure project to use ES6 modules to enable top-level await capabilities. This change helps project to align well with modern JS standards. - Set `type` to `module` in `package.json`. - Use import/export syntax in Cypress configuration files. - Rename configurations files that do not support modules to use the `.cjs` extension: - `vue.config.js` to `vue.config.cjs` (vuejs/vue-cli#4477). - `babel.config.js` to `babel.config.cjs (babel/babel-loader#894) - `.eslintrc.js` to `.eslintrc.cjs` (eslint/eslint#13440, eslint/eslint#14137) - `postcss.config.js` to `postcss.config.cjs` (postcss/postcss#1771) - Provide a workaround for Vue CLI & Mocha ES6 modules conflict in Vue configuration file (vuejs/vue-cli#7417).
Configure project to use ES6 modules to enable top-level await capabilities. This change helps project to align well with modern JS standards. - Set `type` to `module` in `package.json`. - Use import/export syntax in Cypress configuration files. - Rename configurations files that do not support modules to use the `.cjs` extension: - `vue.config.js` to `vue.config.cjs` (vuejs/vue-cli#4477). - `babel.config.js` to `babel.config.cjs (babel/babel-loader#894) - `.eslintrc.js` to `.eslintrc.cjs` (eslint/eslint#13440, eslint/eslint#14137) - `postcss.config.js` to `postcss.config.cjs` (postcss/postcss#1771) - Provide a workaround for Vue CLI & Mocha ES6 modules conflict in Vue configuration file (vuejs/vue-cli#7417).
…1887) <!-- How to write a good PR title: - Follow [the Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). - Give as much context as necessary and as little as possible - Prefix it with [WIP] while it’s a work in progress --> ## Self Checklist - [x] I wrote a PR title in **English** and added an appropriate **label** to the PR. - [x] I wrote the commit message in **English** and to follow [**the Conventional Commits specification**](https://www.conventionalcommits.org/en/v1.0.0/). - [x] I [added the **changeset**](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md) about the changes that needed to be released. (or didn't have to) - [x] I wrote or updated **documentation** related to the changes. (or didn't have to) - [x] I wrote or updated **tests** related to the changes. (or didn't have to) - [x] I tested the changes in various browsers. (or didn't have to) - Windows: Chrome, Edge, (Optional) Firefox - macOS: Chrome, Edge, Safari, (Optional) Firefox ## Related Issue <!-- Please link to issue if one exists --> - Fixes #1884 ## Summary <!-- Please brief explanation of the changes made --> Enchance to add `@layer components` at-rule in CSS post-processing ## Details <!-- Please elaborate description of the changes --> - 커스텀 PostCSS plugin을 통해 CSS를 갈아끼우는 방식으로 구현했습니다. 구현은 단순합니다. - 불필요해진 *.module.scss의 `@layer components` at-rule을 제거했습니다. - `*.module.scss` + `components` 디렉토리 내부에 위치한 파일만 처리하도록 구현했습니다. 여기엔 layout, margin props도 포함되니 이후 디렉터리명 변경에 유의해야합니다. - 이전/이후 빌드된 CSS 파일이 동일한 것을 확인했습니다. ### Breaking change? (Yes/No) <!-- If Yes, please describe the impact and migration path for users --> No ## References <!-- Please list any other resources or points the reviewer should be aware of --> - https://postcss.org/docs/writing-a-postcss-plugin - 공식 홈페이지는 CJS인데, ESM으로 만들기 위해 참고: postcss/postcss#1771
Soooo, does anyone know of any docs / blogs about how to author idiomatic postcss plugins using TypeScript? I haven't come across anything from my searches so far, does everyone just write their plugins in CJS JavaScript? |
You can check out how we do it here : https://github.com/csstools/postcss-plugins summary:
Most basic plugin : https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-base-plugin Rollup stuff : https://github.com/csstools/postcss-plugins/tree/main/rollup |
It's currently unclear how to properly declare a PostCSS module using ES6 module syntax (which TypeScript also uses idiomatically). The suggested
module.exports
isn't idiomatic in these systems.The text was updated successfully, but these errors were encountered: