Skip to content

Commit

Permalink
feat(create-vuestic): tailwind option (#3718)
Browse files Browse the repository at this point in the history
  • Loading branch information
m0ksem authored Aug 29, 2023
1 parent 31c8772 commit 4eed60f
Show file tree
Hide file tree
Showing 16 changed files with 322 additions and 20 deletions.
58 changes: 58 additions & 0 deletions packages/create-vuestic/src/composables/useFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { resolvePath } from "../utils/resolve-path"
import { dirname, resolve } from "path"
import { useUserAnswers } from "./useUserAnswers"
import { mkdir, readFile, writeFile } from "fs/promises"
import { existsSync } from "fs"

export const useFiles = async () => {
const { projectName } = await useUserAnswers()

const resolveCorrectExt = (path: string, ext: string[]) => {
for (const e of ext) {
const resolvedPath = resolve(process.cwd(), projectName, `${path}.${e}`)

if (resolvedPath) {
return resolvedPath
}
}

return null
}

const addFile = async (path: string, content: string) => {
const resolvedPath = resolve(process.cwd(), projectName, path)

const dir = dirname(resolvedPath)

if (!existsSync(dir)) {
await mkdir(dir, { recursive: true })
}

return writeFile(resolvedPath, content, { encoding: 'utf-8', flag: 'wx' })
}

const replaceFileContent = async (path: string, content: (existingContent: string) => string) => {
const resolvedPath = resolvePath(process.cwd(), projectName, path)

if (!resolvedPath) {
throw new Error(`Unexpected error: Could not find ${path}`)
}

const existingContent = (await readFile(resolvedPath)).toString()

return writeFile(resolvedPath, content(existingContent))
}

const addToTopOfFile = async (path: string, content: string) => {
return replaceFileContent(path, (existingContent) => {
return `${content}\n${existingContent}`
})
}

return {
addToTopOfFile,
addFile,
replaceFileContent,
resolveCorrectExt,
}
}
43 changes: 41 additions & 2 deletions packages/create-vuestic/src/composables/usePackageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useUserAnswers } from "./useUserAnswers"

type Package = {
name: string,
dependencies: Record<string, string>,
devDependencies: Record<string, string>,
dependencies?: Record<string, string>,
devDependencies?: Record<string, string>,
}

const sortObjectKeys = (obj: Record<string, string>) => {
Expand All @@ -29,6 +29,7 @@ export const usePackageJson = async () => {
await writeFile(answers.projectName + '/package.json', JSON.stringify(pkg, null, 2))
}

/** @deprecated Use addDependencies to add multiple deps at the same time */
const addDependency = async (name: string, version: string) => {
const pkg = await readPackage()
if (!pkg.dependencies) { pkg.dependencies = {} }
Expand All @@ -38,6 +39,7 @@ export const usePackageJson = async () => {
await writePackage(pkg)
}

/** @deprecated Use addDependencies to add multiple deps at the same time */
const addDevDependency = async (name: string, version: string) => {
const pkg = await readPackage()
if (!pkg.devDependencies) { pkg.devDependencies = {} }
Expand All @@ -47,7 +49,44 @@ export const usePackageJson = async () => {
await writePackage(pkg)
}

const addDependencies = async (deps: {
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
}) => {
const pkg = await readPackage()
if (!pkg.dependencies) { pkg.dependencies = {} }
if (!pkg.devDependencies) { pkg.devDependencies = {} }

if (deps.dependencies) {
pkg.dependencies = {
...pkg.dependencies,
...deps.dependencies,
}
}

if (deps.devDependencies) {
pkg.devDependencies = {
...pkg.devDependencies,
...deps.devDependencies,
}
}

pkg.dependencies = sortObjectKeys(pkg.dependencies)
pkg.devDependencies = sortObjectKeys(pkg.devDependencies)

if (Object.keys(pkg.dependencies).length === 0) {
delete pkg.dependencies
}

if (Object.keys(pkg.devDependencies).length === 0) {
delete pkg.devDependencies
}

await writePackage(pkg)
}

return {
addDependencies,
addDependency,
addDevDependency,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@ export default {
import: [
"import { createVuestic } from 'vuestic-ui'",
],
css: [
'vuestic-ui/css',
],
css: (answers) => {
if (answers.vuesticFeatures.includes('tailwind')) {
return [
'vuestic-ui/styles/essential.css',
'vuestic-ui/styles/typography.css'
]
}

return [
'vuestic-ui/css',
]
},
plugin: 'createVuestic()'
}as Config
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ export default {
'vuestic-ui/styles/essential.css',
]

if (answers.treeShaking.includes('grid')) {
if (answers.treeShaking.includes('grid') && !answers.vuesticFeatures.includes('tailwind')) {
strings.push('vuestic-ui/styles/grid.css')
}

if (answers.treeShaking.includes('normalize')) {
if (answers.treeShaking.includes('normalize') && !answers.vuesticFeatures.includes('tailwind')) {
strings.push('vuestic-ui/styles/reset.css')
}

Expand Down
5 changes: 5 additions & 0 deletions packages/create-vuestic/src/generators/create-nuxt.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { doesSatisfyNodeVersion } from '../utils/node-version';
import { execp } from './../utils/exacp';

export const createNuxt3 = (projectName: string) => {
if (!doesSatisfyNodeVersion('v16.10.0')) {
throw new Error('Nuxt 3 requires Node.js v16.10.0 or higher. Please upgrade your Node.js version.')
}

const command =`npx nuxi init ${projectName}`

return execp(command)
Expand Down
5 changes: 5 additions & 0 deletions packages/create-vuestic/src/generators/create-vue.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { doesSatisfyNodeVersion } from '../utils/node-version';
import { execp } from './../utils/exacp';

type CreateVueFeature = 'ts' | 'jsx' | 'router' | 'pinia' | 'tests' | 'vitest' | 'cypress' | 'playwright' | 'eslint'

export const createVue = async (projectName: string, features: CreateVueFeature[]) => {
if (!doesSatisfyNodeVersion('v16.0.0')) {
throw new Error('Node.js v16.10.0 or higher required. Please upgrade your Node.js version.')
}

const argsString = features
.map((feature) => `--${feature}`)
.join(' ')
Expand Down
2 changes: 2 additions & 0 deletions packages/create-vuestic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { addVuestic } from './steps/2.addVuestic'
import { addAgGrid } from './steps/2.1.addAgGrid'
import { initGit } from "./steps/3.initGit"
import { installDeps } from "./steps/4.installDeps"
import { addTailwind } from "./steps/2.2.addTailwind"

export const main = async () => {
console.log(primaryColor(logo))
Expand All @@ -24,6 +25,7 @@ export const main = async () => {
if (['create-vue', 'nuxt'].includes(answers.projectType)) {
await addVuestic(answers)
await addAgGrid(answers)
await addTailwind(answers)
}
await initGit()
await installDeps()
Expand Down
16 changes: 13 additions & 3 deletions packages/create-vuestic/src/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,29 @@ const questions = definePrompts([
message: 'Vuestic features (can be manually added later)',
initial: 0,
choices: [
{ title: 'Tailwind', value: 'tailwind' as const, description: 'Install Tailwind CSS for styling. We recommend using tailwind instead of grid.css and normalize.css' },
{ title: 'AG Grid', value: 'agGrid' as const, description: 'Install Vuestic AG Grid theme for complex data tables' },
{ title: 'Tree shaking', value: 'treeShaking' as const, description: 'You will need to register each component manually, but it will decrease bundle size' },
],
},
{
type: skipVuesticAdminFn((prev) => prev.includes('treeShaking') ? 'multiselect' : null),
type: skipVuesticAdminFn((prev) => prev.includes('treeShaking') && !prev.includes('tailwind') ? 'multiselect' : null),
name: 'treeShaking' as const,
message: 'Vuestic CSS modules',
initial: 0,
choices: [
{ title: 'typography.css', value: 'typography' as const},
{ title: 'grid.css', value: 'grid' as const, description: 'grid.css is deprecated, use tailwind instead' },
{ title: 'normalize.css', value: 'normalize' as const, description: 'normalize.css is deprecated, use tailwind instead' },
],
},
{
type: skipVuesticAdminFn((prev) => prev.includes('treeShaking') && prev.includes('tailwind') ? 'multiselect' : null),
name: 'treeShaking' as const,
message: 'Vuestic CSS modules',
initial: 0,
choices: [
{ title: 'grid.css', value: 'grid' as const },
{ title: 'typography.css', value: 'typography' as const},
{ title: 'normalize.css', value: 'normalize' as const },
],
},
{
Expand Down
10 changes: 7 additions & 3 deletions packages/create-vuestic/src/steps/2.1.addAgGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ export const addAgGrid = async (options: UserAnswers) => {
return
}

const { addDependency } = await usePackageJson()
const { addDependencies } = await usePackageJson()

await Promise.all([
addDependency('@vuestic/ag-grid-theme', versions['@vuestic/ag-grid-theme'])
addDependencies({
dependencies: {
'@vuestic/ag-grid-theme': versions['@vuestic/ag-grid-theme']
}
})
])
}
128 changes: 128 additions & 0 deletions packages/create-vuestic/src/steps/2.2.addTailwind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { versions } from './../versions';
import { UserAnswers } from './../prompts';
import { usePackageJson } from "../composables/usePackageJson"
import { useFiles } from '../composables/useFiles';

const installInVite = async () => {
const { addFile, resolveCorrectExt, replaceFileContent } = await useFiles()

const css = resolveCorrectExt('src/assets/main', ['css', 'scss', 'sass'])

return Promise.all([
addFile('tailwind.config.js', `
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
screens: {
xs: '0px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
},
},
plugins: [],
}
`.trim()),
addFile('postcss.config.js', `
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
`.trim()),
replaceFileContent(css!, (content) =>
content.replace("@import './base.css';", `
@import './base.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
`.trim())
)
])
}

const installInNuxt = async () => {
const { addFile, resolveCorrectExt, replaceFileContent } = await useFiles()

const nuxtConfig = resolveCorrectExt('nuxt.config', ['ts', 'js'])

return Promise.all([
addFile('tailwind.config.js', `
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./components/**/*.{js,vue,ts}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./nuxt.config.{js,ts}",
"./app.vue",
],
theme: {
extend: {},
screens: {
xs: '0px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
},
},
plugins: [],
}
`.trim()),
addFile('./assets/css/main.css', `
@tailwind base;
@tailwind components;
@tailwind utilities;
`.trim()
),
replaceFileContent(nuxtConfig!, (content) =>
content.replace('export default defineNuxtConfig({', `
export default defineNuxtConfig({
css: ['~/assets/css/main.css'],
postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},
`.trim())
),
])
}

export const addTailwind = async (options: UserAnswers) => {
const { vuesticFeatures, projectType } = options
if (vuesticFeatures && !vuesticFeatures.includes('tailwind')) {
return
}

const { addDependencies } = await usePackageJson()

if (projectType === 'nuxt') {
await installInNuxt()
} else if (projectType === 'create-vue') {
await installInVite()
}

await Promise.all([
addDependencies({
dependencies: {
'@vuestic/tailwind': versions['@vuestic/tailwind'],
},
devDependencies: {
tailwindcss: versions['tailwindcss'],
autoprefixer: versions['autoprefixer'],
postcss: versions['postcss'],
}
}),
])
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const insertNuxtModule = (source: string, css: string[]) => {
}

source = source
.replace(/defineNuxtConfig\({([.|\n]*)}\)/m, (a, b) => a.replace(b, createNuxtConfig(vuesticConfig)))
.replace('defineNuxtConfig({', `defineNuxtConfig({\n ${createNuxtConfig(vuesticConfig)}`)

return source
}
Loading

0 comments on commit 4eed60f

Please sign in to comment.