Skip to content

Commit

Permalink
feat(tailwind): add tailwind-init task
Browse files Browse the repository at this point in the history
* create webpack template file
* update readme
* add tailwind version option
  • Loading branch information
marcjulian committed Aug 17, 2020
1 parent 1b6f2df commit 3aebe1a
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 95 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
src/**/*.js
src/**/*.js.map
src/**/*.d.ts
!src/**/templates/**/*.js

# IDEs
.idea/
Expand Down
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}
44 changes: 42 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Add tailwindcss to your Angular project
# Add Tailwind CSS to your Angular project

Simple Angular schematic that initializes tailwind in your project and adds a custom webpack config to your build process.
Simple [Angular](https://angular.io/) schematic that initializes [Tailwind CSS](https://tailwindcss.com/) in your project and adds a custom webpack config to your build process.

## Installation

Run

Expand All @@ -9,3 +11,41 @@ Run
or optionally

`ng add @garygrossgarten/ngx-tailwind --project <MY_PROJECT>`

## Additional options

You can pass additional flags to customize the schematic. For example, if you want to install a different version for **Tailwind** use `--tailwindVersion` flag:

```bash
ng add @garygrossgarten/ngx-tailwind --tailwindVersion 1.6.2
```

All available flags:

| Flag |  Description | Type |  Default |
| ------------------- | -------------------------------------------- | --------- | ------------------------- |
|  `project` | The project to initialize with Tailwind CSS. | `string` | **First** Angular project |
|  `skipTailwindInit` | Skip initializing Tailwind. | `boolean` | `false` |
|  `tailwindVersion` | The Tailwind version to be installed. | `string` | `latest` |

## Developing

Install `@angular-devkit/schematics-cli` to be able to use `schematics` command

```bash
npm i -g @angular-devkit/schematics-cli
```

Now build the schematics and run the schematic.

```bash
npm run build
# or
npm run build:watch

# dry-run in angular-workspace
npm run start:dev

# execute schematics in angular-workspace
npm run start
```
14 changes: 7 additions & 7 deletions angular-workspace/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 17 additions & 17 deletions angular-workspace/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
module.exports = {
module: {
rules: [
{
test: /.scss$/,
loader: 'postcss-loader',
options: {
ident: 'postcss',
syntax: 'postcss-scss',
plugins: () => [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
]
}
}
]
}
};
rules: [
{
test: /\.scss$/,
loader: 'postcss-loader',
options: {
ident: 'postcss',
syntax: 'postcss-scss',
plugins: () => [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
],
},
},
],
},
};
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"build": "tsc -p tsconfig.json",
"build:watch": "tsc -p tsconfig.json --watch",
"test": "npm run build && jasmine src/**/*_spec.js",
"start": "npm run build && cd angular-workspace && schematics ..:ng-add --debug false"
"start:dev": "npm run build && cd angular-workspace && schematics ..:ng-add",
"start": "npm run build && cd angular-workspace && schematics ..:ng-add --debug false --tailwindVersion 1.6.2"
},
"keywords": [
"schematics"
Expand All @@ -20,9 +21,10 @@
"@schematics/angular": "^8.1.0"
},
"devDependencies": {
"typescript": "~3.8.3",
"@types/jasmine": "^3.3.9",
"@types/node": "^8.0.31",
"jasmine": "^3.3.1"
"jasmine": "^3.3.1",
"prettier": "~2.0.5",
"typescript": "~3.8.3"
}
}
4 changes: 4 additions & 0 deletions src/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"description": "Add tailwind to Angular Project.",
"factory": "./ng-add/index#ngAdd",
"schema": "./ng-add/schema.json"
},
"tailwind-init": {
"description": "Run Tailwind init",
"factory": "./tailwind-init/index#tailwindInit"
}
}
}
117 changes: 51 additions & 66 deletions src/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import {
SchematicContext,
Tree,
chain,
SchematicsException
} from "@angular-devkit/schematics";

import { Schema } from "./schema";
import { NodePackageInstallTask } from "@angular-devkit/schematics/tasks";
SchematicsException,
url,
apply,
mergeWith,
} from '@angular-devkit/schematics';
import { Schema } from './schema';
import {
NodePackageInstallTask,
RunSchematicTask,
} from '@angular-devkit/schematics/tasks';
import {
addPackageJsonDependency,
NodeDependencyType,
} from "@schematics/angular/utility/dependencies";
import { getWorkspace } from "@schematics/angular/utility/workspace";
import { exec } from "child_process";
import { promisify } from "util";
import { ProjectDefinition } from "@angular-devkit/core/src/workspace";
const asyncExec = promisify(exec);
} from '@schematics/angular/utility/dependencies';
import { getWorkspace } from '@schematics/angular/utility/workspace';
import { ProjectDefinition } from '@angular-devkit/core/src/workspace';

export function ngAdd(_options: Schema): Rule {
return async (host: Tree) => {
Expand All @@ -26,59 +28,60 @@ export function ngAdd(_options: Schema): Rule {
if (!projectName) {
throw new SchematicsException('Option "project" is required.');
}
console.log('project name', projectName);

const project = workspace.projects.get(projectName);

if (!project) {
throw new SchematicsException(
`Project ${projectName} is not defined in this workspace.`
`Project ${projectName} is not defined in this workspace.`,
);
}

if (project.extensions["projectType"] !== "application") {
if (project.extensions['projectType'] !== 'application') {
throw new SchematicsException(
`@angular/elements requires a project type of "application" but ${projectName} isn't.`
`@angular/elements requires a project type of "application" but ${projectName} isn't.`,
);
}
return chain([
addDependencies(),
addDependencies(_options),
updateStyles(project),
addWebpackConfig(project),
addWebpackConfig(),
updateAngularJSON(projectName),
install(),
initTailwind(project),
tailwindInit(_options),
]);
};
}
function addDependencies(): Rule {
function addDependencies(_options: Schema): Rule {
return (host: Tree) => {
addPackageJsonDependency(host, {
type: NodeDependencyType.Dev,
name: "tailwindcss",
version: "latest",
name: 'tailwindcss',
version: _options.tailwindVersion,
});
addPackageJsonDependency(host, {
type: NodeDependencyType.Dev,
name: "postcss-scss",
version: "latest",
name: 'postcss-scss',
version: 'latest',
});

addPackageJsonDependency(host, {
type: NodeDependencyType.Dev,
name: "postcss-import",
version: "latest",
name: 'postcss-import',
version: 'latest',
});

addPackageJsonDependency(host, {
type: NodeDependencyType.Dev,
name: "postcss-loader",
version: "latest",
name: 'postcss-loader',
version: 'latest',
});

addPackageJsonDependency(host, {
type: NodeDependencyType.Dev,
name: "ngx-build-plus",
version: "latest",
name: 'ngx-build-plus',
version: 'latest',
});
};
}
Expand All @@ -91,68 +94,50 @@ function updateStyles(project: ProjectDefinition): Rule {
0,
`@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities'; \n`
@import 'tailwindcss/utilities'; \n`,
);
host.commitUpdate(recorder);
};
}

function initTailwind(project: ProjectDefinition): Rule {
return async () => {
try {
await asyncExec(`npx tailwindcss init`, { cwd: project.root });
} catch (e) {
console.error(e);
function tailwindInit(_options: Schema): Rule {
return (_tree: Tree, context: SchematicContext) => {
if (!_options.skipTailwindInit) {
const packageInstall = context.addTask(new NodePackageInstallTask());
context.addTask(new RunSchematicTask('tailwind-init', {}), [
packageInstall,
]);
}
return _tree;
};
}

function addWebpackConfig(project: ProjectDefinition): Rule {
return async (host: Tree) => {
host.create(
project.root + "/webpack.config.js",
`module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loader: 'postcss-loader',
options: {
ident: 'postcss',
syntax: 'postcss-scss',
plugins: () => [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
]
}
}
]
}
};`
);
function addWebpackConfig(): Rule {
return async (_host: Tree) => {
const sourceTemplates = url('./templates/webpack');
const sourceParametrizedTemplates = apply(sourceTemplates, []);
return mergeWith(sourceParametrizedTemplates);
};
}

function updateAngularJSON(project: string): Rule {
return async (host: Tree) => {
const angularConfig = host.read("/angular.json")?.toString();
const angularConfig = host.read('/angular.json')?.toString();
if (angularConfig) {
const json = JSON.parse(angularConfig);
json.projects[project].architect.build.builder =
"ngx-build-plus:browser";
json.projects[project].architect.build.builder = 'ngx-build-plus:browser';
json.projects[project].architect.build.options = {
...json.projects[project].architect.build.options,
extraWebpackConfig: "./webpack.config.js" ,
extraWebpackConfig: './webpack.config.js',
};
json.projects[project].architect.serve.builder =
"ngx-build-plus:dev-server";
'ngx-build-plus:dev-server';
json.projects[project].architect.serve.options = {
...json.projects[project].architect.serve.options,
extraWebpackConfig: "./webpack.config.js" ,
extraWebpackConfig: './webpack.config.js',
};

host.overwrite("/angular.json", JSON.stringify(json, null, 2));
host.overwrite('/angular.json', JSON.stringify(json, null, 2));
}
};
}
Expand Down
Loading

0 comments on commit 3aebe1a

Please sign in to comment.