Open andreavaccari opened 2 years ago
Both ways are valid in PostCSS. The logic is:
()
by writing only require('autoprefixer')
()
require('autoprefixer')({ option: 1 })
PostCSS will detect, that ()
was not called and will call it automatically https://github.com/postcss/postcss/blob/main/lib/postcss.d.ts#L215-L216
Thank you for the quick reply! I assumed this was the intended behavior.
Could I ask you to reproduce the following simple set up?
npm init --yes @svelte-add/kit@latest -- --with tailwindcss test
cd test
sed -i "" "1s/^/console.log('inside tailwind config')\n/" tailwind.config.cjs
npm run dev -- --open
At this point you should see the string inside tailwind config
printed twice to console.
Now please kill the dev server and repeat the following steps.
sed -i "" "s/tailwindcss()/tailwindcss/" postcss.config.cjs
npm run dev -- --open
Now you should see the string inside tailwind config
printed several times to console.
Do you have any insight into why this might be happening?
I got this error during npm init
call.
Can you show me the PostCSS config? Can you show me how do you load this config?
➜ npm init --yes @svelte-add/kit@latest -- --with tailwindcss test
➕ Svelte Add's SvelteKit app initializer (Version 2021.10.02.00)
file:///home/ai/.npm/_npx/9320fb454a84dc6d/node_modules/@svelte-add/create-kit/__init.js:33
if (code !== 0) throw new Error(body);
^
Error: error An unexpected error occurred: "Can't answer a question unless a user TTY".
at ChildProcess.<anonymous> (file:///home/ai/.npm/_npx/9320fb454a84dc6d/node_modules/@svelte-add/create-kit/__init.js:33:25)
at ChildProcess.emit (node:events:390:28)
at maybeClose (node:internal/child_process:1064:16)
at Socket.<anonymous> (node:internal/child_process:450:11)
at Socket.emit (node:events:390:28)
at Pipe.<anonymous> (node:net:672:12)
The error you get seems related to yarn
(ref). The same command should work with npm
(ref).
To answer your question, the command generates this default configuration:
postcss.config.cjs
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const cssnano = require("cssnano");
const mode = process.env.NODE_ENV;
const dev = mode === "development";
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer(),
!dev && cssnano({
preset: "default",
})
],
};
module.exports = config;
tailwind.config.cjs
const config = {
mode: "jit",
purge: ["./src/**/*.{html,js,svelte,ts}"],
theme: {
extend: {}
},
plugins: []
};
module.exports = config;
The error you get seems related to yarn (ref). The same command should work with npm (ref).
I used npm init
there. Maybe script found yarn
in my system and called it?
How I can fix this issue to call code reproducion?
To answer your question, the command generates this default configuration:
Another questions:
inside tailwind config
double call affect end-users?I create a simple repo so you can avoid the npm init
problem:
https://github.com/andreavaccari/postcss-load-config-tailwind
Could you try the following:
npm run dev -- --open
.postcss.config.cjs
, comment the line under option 1, uncomment the line under option 2, and rerun.You should be able to see that in the second case the tailwind.config.cjs
file is loaded several times.
I'm investigating this issue because I have a monorepo with a sluggish DX and I'm trying to figure out if this is part of the issue.
Is it just a performance problem of file multiple loading or it causes some bug? (Don't worry I will not ignore performance issue 😅)
I believe it's only a performance issue. Thank you for being so responsive! 👍
Hello,
the scope of calling tailwindcss should be the tailwind-config object itself. Like here:
`console.log(">>> Loading postcss.config.cjs");
const tailwindConfig = require('./tailwind.config.cjs');
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const cssnano = require("cssnano");
const mode = process.env.NODE_ENV;
const dev = mode === "development";
const config = {
plugins: [
tailwindcss(tailwindConfig),
autoprefixer(),
!dev &&
cssnano({
preset: "default",
}),
],
};
module.exports = config;
console.log(">>> Loading postcss.config.cjs");
I suppose that then tailwindcss called without confing in its scope so the default behaviour of tailwinds is to load the tailwindcss-confing for all its plugins separately. And that's more, the config file is finded by the tailwinds themself.
Do you mind if I pull the request?
Hi @ai, it looks like @WilhelmYakunin is on the right track here. How would you like to proceed?
Hi, @andreavaccari, maybe I can evaporate the question you posed.
The official docs of Tailwindcss prescribe that by default Tailwindcss will look for a tailwind.config.js in the root of a project (please visit here).
Also, postCSS and Tailwindcss work together with having no search for config if the developer clearly puts the config (as an object) or path to config (as string) into tailwindcss function as the first argument. Just read the code of tailwindcss function that is taken from ‘.\node_modules\tailwindcss\lib\index.js’:
module.exports = function tailwindcss(config) {
const resolvedConfigPath = resolveConfigPath(config);
const getConfig = getConfigFunction(resolvedConfigPath || config);
const mode = _lodash.default.get(getConfig(), 'mode', 'aot');
if (mode === 'jit') {
return {
postcssPlugin: 'tailwindcss',
plugins: (0, _jit.default)(config)
};
}
const plugins = [];
if (!_lodash.default.isUndefined(resolvedConfigPath)) {
plugins.push((0, _registerConfigAsDependency.default)(resolvedConfigPath));
}
return {
postcssPlugin: 'tailwindcss',
plugins: [...plugins, (0, _processTailwindFeatures.default)(getConfig), _formatCSS.default]
};
};
module.exports.postCSS = true;
The tailwindcss after invocation is the object, which has the property ‘postCSSplugin’. With the invocation of this object (as it is commonly known in JS functions are objects) a config is ‘undefined’ so the tailwindcss searches into the root folder and finds the config. In this case, the config is loaded once because the function calls only once. Why once? See the second;
When the tailwindcss is written without invocation it is a function (and at the same time a first-class object) but has no property ‘postCSSplugin’. The property ‘postCSSplugin’ will reveal after invocation. So postCSS processor runs it as not an object (case ref) but as a function (case ref). And to process input CSS the postCSS processor needs to run (invocate) tailwindcss as a function. Afterwards, tailwindcss searches for a config because it did not pass into his first arguments (it is the default of tailwindcss). Actually, the posctCSS processor uses the tailwindcss plugin to process not only one css code but also: the code here here and so on. So in the second case, every time postCSS processor works with each of the input CSS it invokes the tailwindcss as the function which searches for config and loads it for every time of its invocation.
If the project root folder wouldn't contain a file which name matches to substring 'tailwindcss-config' (with some of its variations) the tailwindcss will load the defaults config of its own (from stubs folder in tailwindcss node modules, alike here ones ref)
Hi @WilhelmYakunin, thank you so much for taking the time to write this detailed explanation.
I now always invoke tailwind in the config file to avoid the subtly magical behavior of the alternative.
Hi @ai, thank you for your work on
postcss
andautoprefixer
(and your other packages). We're using them in combination with Vite, Svelte, and Tailwind, and we'd appreciate a clarification on how to specify plugins inpostcss.config.cjs
.In this repo (ref), you instruct to require and then invoke a plugin:
In autoprefixer (ref), you instruct to require a plugin without invoking it:
While investigating performance issues with VS Code, I added a
console.log
totailwind.config.cjs
and found that:require('tailwindcss')
, Tailwind's config file is loaded several timesrequire('tailwindcss')()
, Tailwind's config file is loaded only onceQuestion: Could you clarify what is the preferred way to specify plugins?
Thank you for your help!