@astrojs/tailwind: simplify, upgrade & fix support for ts config file (#6724)

Co-authored-by: bluwy <bjornlu.dev@gmail.com>
This commit is contained in:
Tom 2023-06-14 11:55:37 +02:00 committed by GitHub
parent 06315a1fde
commit 3f1cb6b1a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 205 additions and 152 deletions

View file

@ -0,0 +1,34 @@
---
'@astrojs/tailwind': major
---
Let tailwind postcss plugin load its config file itself. This changes the `tailwind.config.js` loading behaviour where Tailwind would load the config file from `process.cwd()` instead of the project `root`. You can configure the integration's `config.path` option to load from a specific path instead.
```js
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import { fileURLToPath } from 'url';
export default defineConfig({
integrations: [
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)),
},
}),
],
});
```
This change also requires a Tailwind config file to exist in your project as Astro's fallback value is no longer provided. It is set up automatically during `astro add tailwind`, but you can also manually create a `tailwind.config.cjs` file in your project root:
```js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [],
}
```

View file

@ -1,9 +1,16 @@
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import { fileURLToPath } from 'url';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind()],
integrations: [
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)),
},
}),
],
vite: {
build: {
assetsInlineLimit: 0,

View file

@ -1,9 +0,0 @@
const path = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: path.join(__dirname, 'tailwind.config.js'), // update this if your path differs!
},
autoprefixer: {}
},
};

View file

@ -1,7 +1,6 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
import { tailwind } from './fixtures/astro-scripts/deps.mjs';
describe('Scripts (hoisted and not)', () => {
describe('Build', () => {
@ -141,7 +140,6 @@ describe('Scripts (hoisted and not)', () => {
fixture = await loadFixture({
root: './fixtures/astro-scripts/',
integrations: [
tailwind(),
{
name: 'test-script-injection-with-injected-route',
hooks: {

View file

@ -1,8 +1,13 @@
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import { fileURLToPath } from 'url';
export default defineConfig({
integrations: [
tailwind()
]
})
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.cjs', import.meta.url)),
},
}),
],
});

View file

@ -1,2 +0,0 @@
export { default as tailwind } from '@astrojs/tailwind';

View file

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [],
}

View file

@ -1,8 +1,14 @@
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import { fileURLToPath } from 'url';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind()],
integrations: [
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.cjs', import.meta.url)),
},
}),
],
});

View file

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [],
}

View file

@ -1,7 +1,14 @@
import { defineConfig } from 'astro/config';
import tailwind from "@astrojs/tailwind";
import tailwind from '@astrojs/tailwind';
import { fileURLToPath } from 'url';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind()]
});
integrations: [
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)),
},
}),
],
});

View file

@ -1,10 +1,18 @@
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import mdx from '@astrojs/mdx';
import { fileURLToPath } from 'url';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind(), mdx()],
integrations: [
tailwind({
config: {
path: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)),
},
}),
mdx(),
],
vite: {
build: {
assetsInlineLimit: 0,

View file

@ -1,10 +0,0 @@
const path = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: path.join(__dirname, 'tailwind.config.js'), // update this if your path differs!
},
autoprefixer: {}
},
};

View file

@ -32,9 +32,8 @@
"dev": "astro-scripts dev \"src/**/*.ts\""
},
"dependencies": {
"@proload/core": "^0.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"postcss": "^8.4.24",
"postcss-load-config": "^4.0.1"
},
"devDependencies": {

View file

@ -1,72 +1,9 @@
import load, { resolve } from '@proload/core';
import type { AstroConfig, AstroIntegration } from 'astro';
import type { AstroIntegration } from 'astro';
import autoprefixerPlugin from 'autoprefixer';
import fs from 'fs/promises';
import path from 'path';
import tailwindPlugin, { type Config as TailwindConfig } from 'tailwindcss';
import resolveConfig from 'tailwindcss/resolveConfig.js';
import { fileURLToPath } from 'url';
import type { ResultPlugin } from 'postcss-load-config';
import tailwindPlugin from 'tailwindcss';
import type { CSSOptions, UserConfig } from 'vite';
function getDefaultTailwindConfig(srcUrl: URL): TailwindConfig {
return resolveConfig({
theme: {
extend: {},
},
plugins: [],
content: [path.join(fileURLToPath(srcUrl), `**`, `*.{astro,html,js,jsx,svelte,ts,tsx,vue}`)],
presets: undefined, // enable Tailwind's default preset
}) as TailwindConfig;
}
async function getUserConfig(root: URL, configPath?: string, isRestart = false) {
const resolvedRoot = fileURLToPath(root);
let userConfigPath: string | undefined;
if (configPath) {
const configPathWithLeadingSlash = /^\.*\//.test(configPath) ? configPath : `./${configPath}`;
userConfigPath = fileURLToPath(new URL(configPathWithLeadingSlash, root));
}
if (isRestart) {
// Hack: Write config to temporary file at project root
// This invalidates and reloads file contents when using ESM imports or "resolve"
const resolvedConfigPath = (await resolve('tailwind', {
mustExist: false,
cwd: resolvedRoot,
filePath: userConfigPath,
})) as string;
const { dir, base } = path.parse(resolvedConfigPath);
const tempConfigPath = path.join(dir, `.temp.${Date.now()}.${base}`);
await fs.copyFile(resolvedConfigPath, tempConfigPath);
let result: load.Config<Record<any, any>> | undefined;
try {
result = await load('tailwind', {
mustExist: false,
cwd: resolvedRoot,
filePath: tempConfigPath,
});
} catch (err) {
console.error(err);
} finally {
await fs.unlink(tempConfigPath);
}
return {
...result,
filePath: resolvedConfigPath,
};
} else {
return await load('tailwind', {
mustExist: false,
cwd: resolvedRoot,
filePath: userConfigPath,
});
}
}
async function getPostCssConfig(
root: UserConfig['root'],
postcssInlineOptions: CSSOptions['postcss']
@ -86,20 +23,19 @@ async function getPostCssConfig(
}
async function getViteConfiguration(
tailwindConfig: TailwindConfig,
viteConfig: AstroConfig['vite']
tailwindConfigPath: string | undefined,
viteConfig: UserConfig
) {
// We need to manually load postcss config files because when inlining the tailwind and autoprefixer plugins,
// that causes vite to ignore postcss config files
const postcssConfigResult = await getPostCssConfig(viteConfig.root, viteConfig.css?.postcss);
const postcssOptions = (postcssConfigResult && postcssConfigResult.options) || {};
const postcssPlugins =
postcssConfigResult && postcssConfigResult.plugins ? postcssConfigResult.plugins.slice() : [];
postcssPlugins.push(tailwindPlugin(tailwindConfig));
const postcssOptions = postcssConfigResult?.options ?? {};
const postcssPlugins = postcssConfigResult?.plugins?.slice() ?? [];
postcssPlugins.push(tailwindPlugin(tailwindConfigPath) as ResultPlugin);
postcssPlugins.push(autoprefixerPlugin());
return {
css: {
postcss: {
@ -123,7 +59,7 @@ type TailwindOptions =
* Disabling this is useful when further customization of Tailwind styles
* and directives is required. See {@link https://tailwindcss.com/docs/functions-and-directives#tailwind Tailwind's docs}
* for more details on directives and customization.
* @default: true
* @default true
*/
applyBaseStyles?: boolean;
};
@ -136,33 +72,10 @@ export default function tailwindIntegration(options?: TailwindOptions): AstroInt
return {
name: '@astrojs/tailwind',
hooks: {
'astro:config:setup': async ({
config,
updateConfig,
injectScript,
addWatchFile,
isRestart,
}) => {
'astro:config:setup': async ({ config, updateConfig, injectScript }) => {
// Inject the Tailwind postcss plugin
const userConfig = await getUserConfig(config.root, customConfigPath, isRestart);
if (customConfigPath && !userConfig?.value) {
throw new Error(
`Could not find a Tailwind config at ${JSON.stringify(
customConfigPath
)}. Does the file exist?`
);
}
if (addWatchFile && userConfig?.filePath) {
addWatchFile(userConfig.filePath);
}
const tailwindConfig =
(userConfig?.value as TailwindConfig) ?? getDefaultTailwindConfig(config.srcDir);
updateConfig({
vite: await getViteConfiguration(tailwindConfig, config.vite),
vite: await getViteConfiguration(customConfigPath, config.vite),
});
if (applyBaseStyles) {

View file

@ -4400,7 +4400,7 @@ importers:
version: 9.2.2
vite:
specifier: ^4.3.1
version: 4.3.1(@types/node@18.16.3)(sass@1.52.2)
version: 4.3.1(@types/node@14.18.21)
packages/integrations/netlify/test/edge-functions/fixtures/dynimport:
dependencies:
@ -4787,18 +4787,15 @@ importers:
packages/integrations/tailwind:
dependencies:
'@proload/core':
specifier: ^0.3.3
version: 0.3.3
autoprefixer:
specifier: ^10.4.14
version: 10.4.14(postcss@8.4.23)
version: 10.4.14(postcss@8.4.24)
postcss:
specifier: ^8.4.23
version: 8.4.23
specifier: ^8.4.24
version: 8.4.24
postcss-load-config:
specifier: ^4.0.1
version: 4.0.1(postcss@8.4.23)
version: 4.0.1(postcss@8.4.24)
devDependencies:
astro:
specifier: workspace:*
@ -4918,7 +4915,7 @@ importers:
version: 3.0.0(vite@4.3.1)(vue@3.2.47)
'@vue/babel-plugin-jsx':
specifier: ^1.1.1
version: 1.1.1(@babel/core@7.21.8)
version: 1.1.1
'@vue/compiler-sfc':
specifier: ^3.2.39
version: 3.2.39
@ -8397,13 +8394,6 @@ packages:
preact: 10.13.2
dev: false
/@proload/core@0.3.3:
resolution: {integrity: sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==}
dependencies:
deepmerge: 4.3.1
escalade: 3.1.1
dev: false
/@rollup/plugin-alias@3.1.9(rollup@2.79.1):
resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==}
engines: {node: '>=8.0.0'}
@ -9312,6 +9302,23 @@ packages:
resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==}
dev: false
/@vue/babel-plugin-jsx@1.1.1:
resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
dependencies:
'@babel/helper-module-imports': 7.21.4
'@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.2)
'@babel/template': 7.20.7
'@babel/traverse': 7.18.2
'@babel/types': 7.21.5
'@vue/babel-helper-vue-transform-on': 1.0.2
camelcase: 6.3.0
html-tags: 3.3.1
svg-tags: 1.0.0
transitivePeerDependencies:
- '@babel/core'
- supports-color
dev: false
/@vue/babel-plugin-jsx@1.1.1(@babel/core@7.21.8):
resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
dependencies:
@ -9370,7 +9377,7 @@ packages:
'@vue/shared': 3.2.39
estree-walker: 2.0.2
magic-string: 0.25.9
postcss: 8.4.23
postcss: 8.4.24
source-map: 0.6.1
dev: false
@ -9385,7 +9392,7 @@ packages:
'@vue/shared': 3.2.47
estree-walker: 2.0.2
magic-string: 0.25.9
postcss: 8.4.23
postcss: 8.4.24
source-map: 0.6.1
/@vue/compiler-ssr@3.2.39:
@ -9784,6 +9791,22 @@ packages:
postcss: 8.4.23
postcss-value-parser: 4.2.0
/autoprefixer@10.4.14(postcss@8.4.24):
resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.5
caniuse-lite: 1.0.30001487
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
postcss: 8.4.24
postcss-value-parser: 4.2.0
dev: false
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@ -15239,6 +15262,23 @@ packages:
postcss: 8.4.23
yaml: 2.2.2
/postcss-load-config@4.0.1(postcss@8.4.24):
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 2.1.0
postcss: 8.4.24
yaml: 2.2.2
dev: false
/postcss-logical@5.0.4(postcss@8.4.23):
resolution: {integrity: sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==}
engines: {node: ^12 || ^14 || >=16}
@ -15416,6 +15456,14 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
/postcss@8.4.24:
resolution: {integrity: sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.6
picocolors: 1.0.0
source-map-js: 1.0.2
/preact-render-to-string@5.2.4(preact@10.13.2):
resolution: {integrity: sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==}
peerDependencies:
@ -17602,6 +17650,39 @@ packages:
- supports-color
dev: false
/vite@4.3.1(@types/node@14.18.21):
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
less: '*'
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
'@types/node': 14.18.21
esbuild: 0.17.18
postcss: 8.4.23
rollup: 3.21.8
optionalDependencies:
fsevents: 2.3.2
dev: true
/vite@4.3.1(@types/node@18.16.3)(sass@1.52.2):
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
engines: {node: ^14.18.0 || >=16.0.0}