diff --git a/jest.config.js b/jest.config.js index c8e9ed9b..7fe4f5b6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,12 @@ +const esModules = ['@ngneat/tailwind'].join('|') + module.exports = { testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], testTimeout: 600000, transform: { '^.+\\.(ts|js|html)$': 'ts-jest', }, + transformIgnorePatterns: [`/node_modules/(?!${esModules})`], resolver: '@nrwl/jest/plugins/resolver', moduleFileExtensions: ['ts', 'js', 'html'], coverageReporters: ['html'], diff --git a/package.json b/package.json index 89c8fd3a..16b1fc45 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "yaml": "^1.10.0" }, "devDependencies": { + "@ngneat/tailwind": "^1.1.0", "@nrwl/angular": "10.4.4", "@nrwl/cli": "10.4.4", "@nrwl/eslint-plugin-nx": "10.4.4", diff --git a/packages/cli/src/lib/cli.ts b/packages/cli/src/lib/cli.ts index 29bd4f27..840954ef 100644 --- a/packages/cli/src/lib/cli.ts +++ b/packages/cli/src/lib/cli.ts @@ -2,6 +2,7 @@ import { basename } from 'path' import * as yargs from 'yargs' import { workspaceInit } from './commands/workspace-init' import { workspaceLint } from './commands/workspace-lint' +import { WebStyleLibrary } from './interfaces' yargs .command( @@ -13,9 +14,18 @@ yargs type: 'string', demandOption: true, }, + webStyleLibrary: { + type: 'string', + demandOption: false, + default: 'bootstrap', + }, }, async (args) => { - await workspaceInit({ dryRun: !!args.dryRun, name: args.name }) + await workspaceInit({ + dryRun: !!args.dryRun, + name: args.name, + webStyleLibrary: args.webStyleLibrary as WebStyleLibrary, + }) }, ) .command( diff --git a/packages/cli/src/lib/commands/workspace-init.ts b/packages/cli/src/lib/commands/workspace-init.ts index 231ae404..6a7f24e5 100644 --- a/packages/cli/src/lib/commands/workspace-init.ts +++ b/packages/cli/src/lib/commands/workspace-init.ts @@ -2,6 +2,7 @@ import { bold, gray, inverse, magentaBright, white, cyanBright } from 'chalk' import { execSync } from 'child_process' import { existsSync } from 'fs-extra' import { join } from 'path' +import { WebStyleLibrary } from '../interfaces' function log(...msg) { console.log(magentaBright('>'), inverse(magentaBright(bold(` NXPM `))), ...msg) @@ -16,7 +17,15 @@ function info(message: string) { log(inverse(cyanBright(bold(` INFO `))), white(message)) } -export async function workspaceInit({ dryRun, name }: { dryRun: boolean; name: string }) { +export async function workspaceInit({ + dryRun, + name, + webStyleLibrary, +}: { + dryRun: boolean + name: string + webStyleLibrary: WebStyleLibrary +}) { const target = join(process.cwd(), name) if (existsSync(target)) { throw new Error(`Path ${target} already exists`) @@ -28,7 +37,12 @@ export async function workspaceInit({ dryRun, name }: { dryRun: boolean; name: s runCommand(createCommand) log('Install dependencies') - const installDeps = `yarn add -D @nxpm/stack @nrwl/angular @nrwl/nest` + const deps = ['@nxpm/stack', '@nrwl/angular', '@nrwl/nest'] + if (webStyleLibrary === 'tailwind') { + deps.push('@ngneat/tailwind') + } + + const installDeps = `yarn add -D ${deps.join(' ')}` runCommand(installDeps, target) log('Initialize @nxpm/stack') diff --git a/packages/cli/src/lib/interfaces/index.ts b/packages/cli/src/lib/interfaces/index.ts new file mode 100644 index 00000000..ccd2a0d5 --- /dev/null +++ b/packages/cli/src/lib/interfaces/index.ts @@ -0,0 +1 @@ +export type WebStyleLibrary = 'bootstrap' | 'tailwind' diff --git a/packages/stack/src/schematics/init/schema.d.ts b/packages/stack/src/schematics/init/schema.d.ts index 8e823b11..b395cf3a 100644 --- a/packages/stack/src/schematics/init/schema.d.ts +++ b/packages/stack/src/schematics/init/schema.d.ts @@ -1,6 +1,7 @@ export interface InitSchematicSchema { name: string ci?: 'github' | 'none' + webStyleLibrary?: 'bootstrap' | 'tailwind' tags?: string directory?: string } diff --git a/packages/stack/src/schematics/init/schema.json b/packages/stack/src/schematics/init/schema.json index 6a387c2e..4a4663fc 100644 --- a/packages/stack/src/schematics/init/schema.json +++ b/packages/stack/src/schematics/init/schema.json @@ -28,6 +28,25 @@ "type": "string", "description": "A directory where the project is placed", "alias": "d" + }, + "library": { + "description": "The UI library", + "type": "string", + "default": "bootstrap", + "x-prompt": { + "message": "Which type of library would you like to ise?", + "type": "list", + "items": [ + { + "value": "bootstrap", + "label": "Bootstrap" + }, + { + "value": "tailwind", + "label": "Tailwind" + } + ] + } } }, "required": ["name"] diff --git a/packages/stack/src/schematics/web-style/files/src/index.scss__tmpl__ b/packages/stack/src/schematics/web-style/files/bootstrap/src/index.scss__tmpl__ similarity index 100% rename from packages/stack/src/schematics/web-style/files/src/index.scss__tmpl__ rename to packages/stack/src/schematics/web-style/files/bootstrap/src/index.scss__tmpl__ diff --git a/packages/stack/src/schematics/web-style/files/src/lib/_global.scss__tmpl__ b/packages/stack/src/schematics/web-style/files/bootstrap/src/lib/_global.scss__tmpl__ similarity index 100% rename from packages/stack/src/schematics/web-style/files/src/lib/_global.scss__tmpl__ rename to packages/stack/src/schematics/web-style/files/bootstrap/src/lib/_global.scss__tmpl__ diff --git a/packages/stack/src/schematics/web-style/files/tailwind/src/index.scss__tmpl__ b/packages/stack/src/schematics/web-style/files/tailwind/src/index.scss__tmpl__ new file mode 100644 index 00000000..a31e4441 --- /dev/null +++ b/packages/stack/src/schematics/web-style/files/tailwind/src/index.scss__tmpl__ @@ -0,0 +1,3 @@ +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; diff --git a/packages/stack/src/schematics/web-style/schema.d.ts b/packages/stack/src/schematics/web-style/schema.d.ts index bbc810a9..d2832f14 100644 --- a/packages/stack/src/schematics/web-style/schema.d.ts +++ b/packages/stack/src/schematics/web-style/schema.d.ts @@ -3,5 +3,6 @@ export interface WebStyleSchematicSchema { name: string tags?: string directory?: string + library?: 'bootstrap' | 'tailwind' removeArchitects?: boolean } diff --git a/packages/stack/src/schematics/web-style/schema.json b/packages/stack/src/schematics/web-style/schema.json index 1a641783..960f75ac 100644 --- a/packages/stack/src/schematics/web-style/schema.json +++ b/packages/stack/src/schematics/web-style/schema.json @@ -27,6 +27,25 @@ "type": "string", "description": "A directory where the project is placed", "alias": "d" + }, + "library": { + "description": "The UI library", + "type": "string", + "default": "bootstrap", + "x-prompt": { + "message": "Which type of library would you like to ise?", + "type": "list", + "items": [ + { + "value": "bootstrap", + "label": "Bootstrap" + }, + { + "value": "tailwind", + "label": "Tailwind" + } + ] + } } }, "required": ["appName", "name"] diff --git a/packages/stack/src/schematics/web-style/schematic-web-style.spec.ts b/packages/stack/src/schematics/web-style/schematic-web-style.spec.ts index 31166139..26955660 100644 --- a/packages/stack/src/schematics/web-style/schematic-web-style.spec.ts +++ b/packages/stack/src/schematics/web-style/schematic-web-style.spec.ts @@ -20,3 +20,21 @@ describe('web-style schematic', () => { await expect(testRunner.runSchematicAsync('web-style', options, app).toPromise()).resolves.not.toThrowError() }) }) + +describe('web-style schematic with tailwind', () => { + let appTree: Tree + const options: WebStyleSchematicSchema = { name: 'style', appName: 'test2', library: 'tailwind' } + + const testRunner = new SchematicTestRunner('@nxpm/web-style', join(__dirname, '../../../collection.json')) + + beforeEach(() => { + appTree = createEmptyWorkspace(Tree.empty()) + }) + + it('should add and run @ngneat/tailwind schematic', async () => { + const app = await testRunner.runSchematicAsync('web', { name: 'test2' }, appTree).toPromise() + await expect(testRunner.runSchematicAsync('web-style', options, app).toPromise()).resolves.not.toThrowError() + expect(app.exists('tailwind.config.js')).toBeDefined() + expect(app.exists('webpack.config.js')).toBeDefined() + }) +}) diff --git a/packages/stack/src/schematics/web-style/schematic-web-style.ts b/packages/stack/src/schematics/web-style/schematic-web-style.ts index 6f33608e..db12f6c8 100644 --- a/packages/stack/src/schematics/web-style/schematic-web-style.ts +++ b/packages/stack/src/schematics/web-style/schematic-web-style.ts @@ -1,10 +1,11 @@ -import { chain, Rule, schematic } from '@angular-devkit/schematics' +import { chain, externalSchematic, noop, Rule, schematic } from '@angular-devkit/schematics' import { addDepsToPackageJson, ProjectType } from '@nrwl/workspace' import { addFiles, normalizeOptions, removeFiles, updateAppStyles, updateProjectArchitects } from '../../utils' import { WebStyleSchematicSchema } from './schema' export default function (options: WebStyleSchematicSchema): Rule { const name = options.name || 'style' + const library = options.library || 'bootstrap' const appName = options.appName const projectName = appName ? `${appName}-${name}` : name const directory = options.directory || options.name @@ -23,7 +24,10 @@ export default function (options: WebStyleSchematicSchema): Rule { name, type: 'style', }), - addFiles(normalizedOptions), + library === 'tailwind' + ? externalSchematic('@ngneat/tailwind', 'ng-add', { project: appName, cssFlavor: 'scss' }) + : noop(), + addFiles(normalizedOptions, `./files/${library}`), updateAppStyles(appName, [`apps/${appName}/src/styles.scss`, `libs/${appName}/${name}/src/index.scss`]), updateProjectArchitects(projectName), removeFiles( diff --git a/packages/stack/src/utils/index.ts b/packages/stack/src/utils/index.ts index 82560f22..d2db6231 100644 --- a/packages/stack/src/utils/index.ts +++ b/packages/stack/src/utils/index.ts @@ -96,9 +96,9 @@ export function appendToPath(path, line: string | string[]): Rule { } } -export function addFiles(options: NormalizedSchema): Rule { +export function addFiles(options: NormalizedSchema, path = './files'): Rule { return mergeWith( - apply(url(`./files`), [ + apply(url(path), [ template({ ...strings, ...options, diff --git a/yarn.lock b/yarn.lock index ecb6452a..df80b8e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -67,6 +67,15 @@ ora "4.0.3" rxjs "6.5.4" +"@angular/cdk@10.2.5": + version "10.2.5" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-10.2.5.tgz#768204ff4db1282297d15f382970f151f87434ec" + integrity sha512-SI/YdaxfkttG92A0uGRixyJkfTKHn0GIU+7BCSRq0d31ru3Ugfln+jr+5/xttxWr88CNPTfpGaUt0ZuSqYCzqw== + dependencies: + tslib "^2.0.0" + optionalDependencies: + parse5 "^5.0.0" + "@angular/cli@^9.1.6": version "9.1.12" resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-9.1.12.tgz#c6e41c80c387200766fc52a6b42fde869dcc0cef" @@ -1206,6 +1215,18 @@ fs-extra "9.0.1" pluralize "8.0.0" +"@ngneat/tailwind@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@ngneat/tailwind/-/tailwind-1.1.0.tgz#ce082f395cc2201d212c880f4df92e8cf050d50d" + integrity sha512-nUQPGffa5kG47GgMljj31P9wR7/4b9YDjfqspdttydbVmUA8INhVBrh7Kkp7IGjvS8KKwp/P2EkAxiMlbfm8hA== + dependencies: + "@angular-devkit/core" "10.1.7" + "@angular-devkit/schematics" "10.1.7" + "@angular/cdk" "10.2.5" + "@schematics/angular" "10.1.7" + rxjs "6.6.3" + typescript "4.0.3" + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -1579,15 +1600,7 @@ dependencies: "@types/node" ">= 8" -"@schematics/angular@9.1.12": - version "9.1.12" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.1.12.tgz#608e25dbd517d867002781f695336b51f05417a2" - integrity sha512-r4+aPAGhstsKFMwW/kOen1ACnzuLpz+vMxEpndXOqqVXLkAMsuAbQUFYjIlMy6fH4zdhpI90EJZ1PbOrAXvKxA== - dependencies: - "@angular-devkit/core" "9.1.12" - "@angular-devkit/schematics" "9.1.12" - -"@schematics/angular@~10.1.3": +"@schematics/angular@10.1.7", "@schematics/angular@~10.1.3": version "10.1.7" resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-10.1.7.tgz#f7794b8f27ae48f7fce991e289b9fec8700eae49" integrity sha512-jcyLWDSbpgHvB/BNVSsV4uLJpC2qRx9Z5+rcQpBB1BerqIPS/1cTQg7TViHZtcqnZqWvzHR3jfqzDUSOCZpuJQ== @@ -1596,6 +1609,14 @@ "@angular-devkit/schematics" "10.1.7" jsonc-parser "2.3.0" +"@schematics/angular@9.1.12": + version "9.1.12" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.1.12.tgz#608e25dbd517d867002781f695336b51f05417a2" + integrity sha512-r4+aPAGhstsKFMwW/kOen1ACnzuLpz+vMxEpndXOqqVXLkAMsuAbQUFYjIlMy6fH4zdhpI90EJZ1PbOrAXvKxA== + dependencies: + "@angular-devkit/core" "9.1.12" + "@angular-devkit/schematics" "9.1.12" + "@schematics/update@0.901.12": version "0.901.12" resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.901.12.tgz#7e410ac7a163b71e30d8cc56d7959adf9225078c" @@ -7874,7 +7895,7 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" -parse5@5.1.1: +parse5@5.1.1, parse5@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== @@ -8783,7 +8804,7 @@ rxjs@6.6.2: dependencies: tslib "^1.9.0" -rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.5.4, rxjs@^6.6.0, rxjs@^6.6.3: +rxjs@6.6.3, rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.5.4, rxjs@^6.6.0, rxjs@^6.6.3: version "6.6.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== @@ -9952,6 +9973,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" + integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg== + typescript@~4.0.3: version "4.0.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389"