From f4b5b3fbc47fe856dfd6baf3e90cf2e2d6b75899 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Fri, 20 Oct 2023 21:25:41 -0500 Subject: [PATCH] feat(cli): support `tailwind.config.mjs` file (#120) * feat(cli): support `tailwind.config.mjs` file * feat: update * fix: teest case --------- Co-authored-by: sadeghbarati --- packages/cli/src/commands/init.ts | 17 ++- packages/cli/src/utils/get-config.ts | 1 + packages/cli/src/utils/templates.ts | 18 ++- .../transformers/transform-cjs-to-esm.ts | 8 + .../transform-cjs-to-esm.test.ts.snap | 139 ++++++++++++++++++ .../test/utils/transform-cjs-to-esm.test.ts | 8 + 6 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 packages/cli/src/utils/transformers/transform-cjs-to-esm.ts create mode 100644 packages/cli/test/utils/__snapshots__/transform-cjs-to-esm.test.ts.snap create mode 100644 packages/cli/test/utils/transform-cjs-to-esm.test.ts diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 052fee3f..c4298f58 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -28,6 +28,7 @@ import { rawConfigSchema, resolveConfigPaths, } from '../utils/get-config' +import { transformCJSToESM } from '../utils/transformers/transform-cjs-to-esm' const PROJECT_DEPENDENCIES = { base: [ @@ -110,6 +111,7 @@ export async function promptForConfig( { title: 'Vite', value: 'vite' }, { title: 'Nuxt', value: 'nuxt' }, { title: 'Laravel', value: 'laravel' }, + { title: 'Astro', value: 'astro' }, ], }, { @@ -136,7 +138,7 @@ export async function promptForConfig( type: 'text', name: 'tailwindCss', message: `Where is your ${highlight('Tailwind CSS')} file?`, - initial: (prev, values) => defaultConfig?.tailwind.css ?? TAILWIND_CSS_PATH[values.framework as 'vite' | 'nuxt' | 'laravel'], + initial: (prev, values) => defaultConfig?.tailwind.css ?? TAILWIND_CSS_PATH[values.framework as 'vite' | 'nuxt' | 'laravel' | 'astro'], }, { type: 'toggle', @@ -151,8 +153,8 @@ export async function promptForConfig( { type: 'text', name: 'tailwindConfig', - message: `Where is your ${highlight('tailwind.config.js')} located?`, - initial: defaultConfig?.tailwind.config ?? DEFAULT_TAILWIND_CONFIG, + message: `Where is your ${highlight('tailwind.config')} located?`, + initial: (prev, values) => defaultConfig?.tailwind.config ?? values.framework === 'astro' ? 'tailwind.config.mjs' : DEFAULT_TAILWIND_CONFIG, }, { type: 'text', @@ -235,9 +237,12 @@ export async function runInit(cwd: string, config: Config) { // Write tailwind config. await fs.writeFile( config.resolvedPaths.tailwindConfig, - config.tailwind.cssVariables - ? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework }) - : template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework }), + transformCJSToESM( + config.resolvedPaths.tailwindConfig, + config.tailwind.cssVariables + ? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework }) + : template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework }), + ), 'utf8', ) diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts index c85e36f7..68f7ebeb 100644 --- a/packages/cli/src/utils/get-config.ts +++ b/packages/cli/src/utils/get-config.ts @@ -16,6 +16,7 @@ export const TAILWIND_CSS_PATH = { nuxt: 'assets/css/tailwind.css', vite: 'src/assets/index.css', laravel: 'resources/css/app.css', + astro: 'src/styles/globals.css', } // TODO: Figure out if we want to support all cosmiconfig formats. diff --git a/packages/cli/src/utils/templates.ts b/packages/cli/src/utils/templates.ts index 3ebd2edd..a13aa270 100644 --- a/packages/cli/src/utils/templates.ts +++ b/packages/cli/src/utils/templates.ts @@ -7,7 +7,10 @@ export function cn(...inputs: ClassValue[]) { } ` -export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */ +export const TAILWIND_CONFIG = ` +const animate = require("tailwindcss-animate") + +/** @type {import('tailwindcss').Config} */ module.exports = { darkMode: ["class"], content: [ @@ -41,10 +44,13 @@ module.exports = { }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [animate], }` -export const TAILWIND_CONFIG_WITH_VARIABLES = `/** @type {import('tailwindcss').Config} */ +export const TAILWIND_CONFIG_WITH_VARIABLES = `\n +const animate = require("tailwindcss-animate") + +/** @type {import('tailwindcss').Config} */ module.exports = { darkMode: ["class"], <% if (framework === 'vite') { %> @@ -61,6 +67,10 @@ module.exports = { "./resources/views/**/*.blade.php", "./resources/js/**/*.{<%- extension %>,<%- extension %>x,vue}", ], + <% } else if (framework === 'astro') { %> + content: [ + './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}', + ], <% } %> theme: { container: { @@ -127,5 +137,5 @@ module.exports = { }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [animate], }` diff --git a/packages/cli/src/utils/transformers/transform-cjs-to-esm.ts b/packages/cli/src/utils/transformers/transform-cjs-to-esm.ts new file mode 100644 index 00000000..1966e4c7 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-cjs-to-esm.ts @@ -0,0 +1,8 @@ +export function transformCJSToESM(filename: string, code: string) { + if (filename.endsWith('.mjs')) { + return code + .replace(/const\s([\w\d_]+)\s*=\s*require\((.*)\);?/g, 'import $1 from $2') + .replace(/module\.exports = /g, 'export default ') + } + return code +} diff --git a/packages/cli/test/utils/__snapshots__/transform-cjs-to-esm.test.ts.snap b/packages/cli/test/utils/__snapshots__/transform-cjs-to-esm.test.ts.snap new file mode 100644 index 00000000..0e927a78 --- /dev/null +++ b/packages/cli/test/utils/__snapshots__/transform-cjs-to-esm.test.ts.snap @@ -0,0 +1,139 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`handle tailwind config template correctly 1`] = ` +" +import animate from \\"tailwindcss-animate\\" + +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: [\\"class\\"], + content: [ + './pages/**/*.{<%- extension %>,<%- extension %>x,vue}', + './components/**/*.{<%- extension %>,<%- extension %>x,vue}', + './app/**/*.{<%- extension %>,<%- extension %>x,vue}', + './src/**/*.{<%- extension %>,<%- extension %>x,vue}', + ], + theme: { + container: { + center: true, + padding: \\"2rem\\", + screens: { + \\"2xl\\": \\"1400px\\", + }, + }, + extend: { + keyframes: { + \\"accordion-down\\": { + from: { height: 0 }, + to: { height: \\"var(--radix-accordion-content-height)\\" }, + }, + \\"accordion-up\\": { + from: { height: \\"var(--radix-accordion-content-height)\\" }, + to: { height: 0 }, + }, + }, + animation: { + \\"accordion-down\\": \\"accordion-down 0.2s ease-out\\", + \\"accordion-up\\": \\"accordion-up 0.2s ease-out\\", + }, + }, + }, + plugins: [animate], +}" +`; + +exports[`handle tailwind config template correctly 2`] = ` +" + +import animate from \\"tailwindcss-animate\\" + +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: [\\"class\\"], + <% if (framework === 'vite') { %> + content: [ + './pages/**/*.{<%- extension %>,<%- extension %>x,vue}', + './components/**/*.{<%- extension %>,<%- extension %>x,vue}', + './app/**/*.{<%- extension %>,<%- extension %>x,vue}', + './src/**/*.{<%- extension %>,<%- extension %>x,vue}', + ], + <% } else if (framework === 'laravel') { %> + content: [ + \\"./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php\\", + \\"./storage/framework/views/*.php\\", + \\"./resources/views/**/*.blade.php\\", + \\"./resources/js/**/*.{<%- extension %>,<%- extension %>x,vue}\\", + ], + <% } else if (framework === 'astro') { %> + content: [ + './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}', + ], + <% } %> + theme: { + container: { + center: true, + padding: \\"2rem\\", + screens: { + \\"2xl\\": \\"1400px\\", + }, + }, + extend: { + colors: { + border: \\"hsl(var(--border))\\", + input: \\"hsl(var(--input))\\", + ring: \\"hsl(var(--ring))\\", + background: \\"hsl(var(--background))\\", + foreground: \\"hsl(var(--foreground))\\", + primary: { + DEFAULT: \\"hsl(var(--primary))\\", + foreground: \\"hsl(var(--primary-foreground))\\", + }, + secondary: { + DEFAULT: \\"hsl(var(--secondary))\\", + foreground: \\"hsl(var(--secondary-foreground))\\", + }, + destructive: { + DEFAULT: \\"hsl(var(--destructive))\\", + foreground: \\"hsl(var(--destructive-foreground))\\", + }, + muted: { + DEFAULT: \\"hsl(var(--muted))\\", + foreground: \\"hsl(var(--muted-foreground))\\", + }, + accent: { + DEFAULT: \\"hsl(var(--accent))\\", + foreground: \\"hsl(var(--accent-foreground))\\", + }, + popover: { + DEFAULT: \\"hsl(var(--popover))\\", + foreground: \\"hsl(var(--popover-foreground))\\", + }, + card: { + DEFAULT: \\"hsl(var(--card))\\", + foreground: \\"hsl(var(--card-foreground))\\", + }, + }, + borderRadius: { + lg: \\"var(--radius)\\", + md: \\"calc(var(--radius) - 2px)\\", + sm: \\"calc(var(--radius) - 4px)\\", + }, + keyframes: { + \\"accordion-down\\": { + from: { height: 0 }, + to: { height: \\"var(--radix-accordion-content-height)\\" }, + }, + \\"accordion-up\\": { + from: { height: \\"var(--radix-accordion-content-height)\\" }, + to: { height: 0 }, + }, + }, + animation: { + \\"accordion-down\\": \\"accordion-down 0.2s ease-out\\", + \\"accordion-up\\": \\"accordion-up 0.2s ease-out\\", + }, + }, + }, + plugins: [animate], +}" +`; diff --git a/packages/cli/test/utils/transform-cjs-to-esm.test.ts b/packages/cli/test/utils/transform-cjs-to-esm.test.ts new file mode 100644 index 00000000..ede5c9d8 --- /dev/null +++ b/packages/cli/test/utils/transform-cjs-to-esm.test.ts @@ -0,0 +1,8 @@ +import { expect, test } from 'vitest' +import { TAILWIND_CONFIG, TAILWIND_CONFIG_WITH_VARIABLES } from '../../src/utils/templates' +import { transformCJSToESM } from '../../src/utils/transformers/transform-cjs-to-esm' + +test('handle tailwind config template correctly', () => { + expect(transformCJSToESM('.mjs', TAILWIND_CONFIG)).toMatchSnapshot() + expect(transformCJSToESM('.mjs', TAILWIND_CONFIG_WITH_VARIABLES)).toMatchSnapshot() +})