UNPKG

9.39 kBMarkdownView Raw
1# EsifyCSS
2
3[![CircleCI](https://circleci.com/gh/kei-ito/esifycss.svg?style=svg)](https://circleci.com/gh/kei-ito/esifycss)
4[![Build Status](https://travis-ci.com/kei-ito/esifycss.svg?branch=master)](https://travis-ci.com/kei-ito/esifycss)
5[![Build status](https://ci.appveyor.com/api/projects/status/g4839cvn53ph9boi/branch/master?svg=true)](https://ci.appveyor.com/project/kei-ito/esifycss/branch/master)
6[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=WDQvOHgwbkRNTUFyUVkrc0RmdGgva0diVk01Tm9LWU95ZFNGVTByeHhpVT0tLUc2RW9lNnNaY2k4QkVCSjMyalRGTVE9PQ==--007efb48774305e72904bb3a15d3b0d048dbfb91)](https://www.browserstack.com/automate/public-build/WDQvOHgwbkRNTUFyUVkrc0RmdGgva0diVk01Tm9LWU95ZFNGVTByeHhpVT0tLUc2RW9lNnNaY2k4QkVCSjMyalRGTVE9PQ==--007efb48774305e72904bb3a15d3b0d048dbfb91)
7[![codecov](https://codecov.io/gh/kei-ito/esifycss/branch/master/graph/badge.svg)](https://codecov.io/gh/kei-ito/esifycss)
8
9## Introduction
10
11EsifyCSS finds CSS files in your project and generates ES modules for each of
12them.
13
14Assume that you have `src/style1.css` and `src/style2.css`. They have the same
15contents:
16
17```css
18/* src/style1.css, src/style2.css */
19@keyframes FadeIn {
20 0%: {opacity: 0}
21 100%: {opacity: 0}
22}
23@keyframes Rotate {
24 0%: {transform: rotate( 0deg)}
25 100%: {transform: rotate(360deg)}
26}
27#container {
28 animation: 0.2s linear FadeIn;
29}
30.icon {
31 animation-duration: 1s;
32 animation-iteration-count: infinite;
33 animation-timing-function: linear;
34}
35.icon.rotate {
36 animation-name: Rotate;
37}
38```
39
40Then, run `esifycss --helper src/helper.js src`. `--helper src/helper.js` is
41where the helper script is written. The last `src` specifies the directory that
42contains the file to be processed by EsifyCSS.
43
44The process finds CSS files, parses them, extracts identifiers, replaces them with
45 values.
46
47After the process, you'll get `src/style1.css.js` and `src/style2.css.js`:
48
49```javascript
50// src/style1.css.js
51import {addStyle} from './helper.js';
52addStyle(["WYIGqCCQSCaAQEcSCaAUEE","WYIGsCCQSCeAgBiBIIQkBmBEcSCeAgBiByBkBmBEE","0BGQC2BA4BKOA6BoBIqBIGqCKE","sBGUCOM8BAUoBKOM+BMgCAiCKOMkCMmCAqBKE","sBG2CG4CCOMoCAGsCKE"]);
53export const className = {
54 "icon": "_1",
55 "rotate": "_2"
56};
57export const id = {
58 "container": "_0"
59};
60export const keyframes = {
61 "FadeIn": "_3",
62 "Rotate": "_4"
63};
64```
65
66```javascript
67// src/style2.css.js
68import {addStyle} from './helper.js';
69addStyle(["WYIGuBCQSCaAQEcSCaAUEE","WYIGwBCQSCeAgBiBIIQkBmBEcSCeAgBiByBkBmBEE","0BGuCC2BA4BKOA6BoBIqBIGuBKE","sBGwCCOM8BAUoBKOM+BMgCAiCKOMkCMmCAqBKE","sBGyCG0CCOMoCAGwBKE"]);
70export const className = {
71 "icon": "_6",
72 "rotate": "_7"
73};
74export const id = {
75 "container": "_5"
76};
77export const keyframes = {
78 "FadeIn": "_8",
79 "Rotate": "_9"
80};
81```
82
83The two modules are almost the same, but the exported objects are different. And
84there will be `src/helper.js` which exports the `addStyle` function which
85applies the style to documents. You can see the code at
86[sample/01-mangle/helper.js](sample/01-mangle/helper.js).
87
88The exported objects are mappings of identifiers of `className`, `id`, and
89`keyframes` that were replaced in the process. You should import them and use
90the replaced identifiers instead of original in the code:
91
92```javascript
93import style from './style1.css.js';
94const element = document.createElement('div');
95element.classList.add(style.className.icon);
96```
97
98## Tools
99
100EsifyCSS consists of **PostCSS plugin**, **Runner** and **CLI**.
101
102### PostCSS plugin
103
104The plugin converts the identifiers in CSS and minifies them. It outputs the
105result of minifications using [Root.warn()].
106
107[Root.warn()]: http://api.postcss.org/Root.html#warn
108
109### Runner
110
111A runner process `.css` files in your project with PostCSS and output the
112results to `.css.js` or `.css.ts`.
113
114### CLI
115
116```
117Usage: esifycss [options] <include ...>
118
119Options:
120 -V, --version output the version number
121 --helper <path> A path where the helper script will be output. You can't use --helper with --css.
122 --css <path> A path where the css will be output. You can't use --css with --helper.
123 --ext <ext> An extension of scripts generated from css.
124 --config <path> A path to configuration files.
125 --exclude <path ...> Paths or patterns to be excluded.
126 --noMangle Keep the original name for debugging.
127 --watch Watch files and update the modules automatically.
128 -h, --help output usage information
129```
130
131## Installation
132
133```bash
134npm install --save-dev esifycss
135```
136
137## `@import` Syntax
138
139You can use `@import` syntax if the style declarations requires identifiers
140declared in other files.
141
142For example, Assume you have the following `a.css` and `b.css`.
143
144```css
145/* a.css */
146.container {...} /* → ._0 */
147```
148
149```css
150/* b.css */
151.container {...} /* → ._1 */
152```
153
154The `container` class names will be shortened to unique names like `_0` and
155`_1`. You can import the shortened names with the `@import` syntax.
156
157```css
158/* "modA-" is prefix for a.css */
159@import './a.css' modA-;
160/* "bbbb" is prefix for b.css */
161@import './b.css' BBB;
162.wrapper>.modA-container {...} /* → ._2>._0 */
163.wrapper>.BBBcontainer {...} /* → ._2>._1 */
164```
165
166## JavaScript API for Runner
167
168```javascript
169import {Session} from 'esifycss';
170new Session(options).start()
171.then(() => console.log('Done'))
172.catch((error) => console.error(error));
173```
174
175### Options
176
177```typescript
178export interface ISessionOptions {
179 /**
180 * Pattern(s) to be included
181 * @default "*"
182 */
183 include?: string | Array<string>,
184 /**
185 * Pattern(s) to be excluded.
186 * @default ['node_modules']
187 */
188 exclude?: anymatch.Matcher,
189 /**
190 * File extension(s) to be included.
191 * @default ['.css']
192 */
193 extensions?: Array<string>,
194 /**
195 * Where this plugin outputs the helper script.
196 * If you use TypeScript, set a value like '*.ts'.
197 * You can't use this option with the css option.
198 * The {hash} in the default value is calculated from the include option.
199 * @default "helper.{hash}.css.js"
200 */
201 helper?: string,
202 /**
203 * File extension of generated script.
204 * @default options.helper ? path.extname(options.helper) : '.js'
205 */
206 ext?: string,
207 /**
208 * Where this plugin outputs the css.
209 * You can't use this option with the helper option.
210 * @default undefined
211 */
212 css?: string,
213 /**
214 * It it is true, a watcher is enabled.
215 * @default false
216 */
217 watch?: boolean,
218 /**
219 * Options passed to chokidar.
220 * You can't set ignoreInitial to true.
221 * @default {
222 * ignore: exclude,
223 * ignoreInitial: false,
224 * useFsEvents: false,
225 * }
226 */
227 chokidar?: chokidar.WatchOptions,
228 /**
229 * An array of postcss plugins.
230 * esifycss.plugin is appended to this array.
231 * @default []
232 */
233 postcssPlugins?: Array<postcss.AcceptedPlugin>,
234 /**
235 * https://github.com/postcss/postcss#options
236 * @default undefined
237 */
238 postcssOptions?: postcss.ProcessOptions,
239 /**
240 * Parameters for esifycss.plugin.
241 */
242 esifycssPluginParameter?: IPluginOptions,
243 /**
244 * A stream where the runner outputs logs.
245 * @default process.stdout
246 */
247 stdout?: stream.Writable,
248 /**
249 * A stream where the runner outputs errorlogs.
250 * @default process.stderr
251 */
252 stderr?: stream.Writable,
253}
254```
255
256Source: [src/runner/types.ts](src/runner/types.ts)
257
258## JavaScript API for Plugin
259
260```javascript
261const postcss = require('postcss');
262const esifycss = require('esifycss');
263postcss([
264 esifycss.plugin({/* Plugin Options */}),
265])
266.process(css, {from: '/foo/bar.css'})
267.then((result) => {
268 const pluginResult = esifycss.extractPluginResult(result);
269 console.log(pluginResult);
270 // → {
271 // className: {bar: '_1'},
272 // id: {foo: '_0'},
273 // keyframes: {aaa: '_2'},
274 // }
275});
276```
277
278The code is at [sample/plugin.js](sample/plugin.js).
279You can run it by `node sample/plugin.js` after cloning this repository and
280running `npm run build`.
281
282### Options
283
284```typescript
285export interface IPluginOptions {
286 /**
287 * When it is true, this plugin minifies classnames.
288 * @default true
289 */
290 mangle?: boolean,
291 /**
292 * A function returns an unique number from a given file id. If you process
293 * CSS files in multiple postcss processes, you should create an identifier
294 * outside the processes and pass it as this value to keep the uniqueness
295 * of mangled outputs.
296 * @default esifycss.createIdentifier()
297 */
298 identifier?: IIdentifier,
299 /**
300 * Names starts with this value are not passed to mangler but replaced with
301 * unprefixed names.
302 * @default "raw-"
303 */
304 rawPrefix?: string,
305 /**
306 * A custom mangler: (*id*, *type*, *name*) => string.
307 * - *id*: string. A filepath to the CSS.
308 * - *type*: 'id' | 'class' | 'keyframes'. The type of *name*
309 * - *name*: string. An identifier in the style.
310 *
311 * If mangler is set, `mangle` and `identifier` options are ignored.
312 *
313 * For example, If the plugin processes `.foo{color:green}` in `/a.css`,
314 * The mangler is called with `("/a.css", "class", "foo")`. A mangler should
315 * return an unique string for each input pattern or the styles will be
316 * overwritten unexpectedly.
317 * @default undefined
318 */
319 mangler?: IPluginMangler,
320}
321```
322
323Source: [src/postcssPlugin/types.ts](src/postcssPlugin/types.ts)
324
325## LICENSE
326
327The esifycss project is licensed under the terms of the Apache 2.0 License.