Skip to content

Commit

Permalink
feat: add a CLI and expose the node API (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
zamotany authored and satya164 committed Jan 7, 2019
1 parent 6c32118 commit 8ace1f3
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 62 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Dynamic styles will be applied using CSS custom properties (aka CSS variables) a
- [Bundlers integration](/docs/BUNDLERS_INTEGRATION.md)
- [Webpack](/docs/BUNDLERS_INTEGRATION.md#webpack)
- [Rollup](/docs/BUNDLERS_INTEGRATION.md#rollup)
- [CLI](/docs/CLI.md)
- [Linting](/docs/LINTING.md)
- [How it works](/docs/HOW_IT_WORKS.md)
- [Example](/website)
Expand Down Expand Up @@ -192,9 +193,9 @@ Special thanks to [@kentcdodds](https://github.com/kentcdodds) for his babel plu
Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
| [<img src="https://avatars2.githubusercontent.com/u/17573635?v=4" width="100px;"/><br /><sub>Paweł Trysła</sub>](https://twitter.com/_zamotany)<br />[💻](https://github.com/satya164/linara/commits?author=zamotany "Code") [📖](https://github.com/satya164/linara/commits?author=zamotany "Documentation") [🤔](#ideas-zamotany "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/1174278?v=4" width="100px;"/><br /><sub>Satyajit Sahoo</sub>](https://medium.com/@satya164)<br />[💻](https://github.com/satya164/linara/commits?author=satya164 "Code") [🤔](#ideas-satya164 "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/5106466?v=4" width="100px;"/><br /><sub>Michał Pierzchała</sub>](https://github.com/thymikee)<br />[💻](https://github.com/satya164/linara/commits?author=thymikee "Code") [📖](https://github.com/satya164/linara/commits?author=thymikee "Documentation") [🤔](#ideas-thymikee "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/1909761?v=4" width="100px;"/><br /><sub>Lucas</sub>](https://lcs.sh)<br />[📖](https://github.com/satya164/linara/commits?author=AgtLucas "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/680439?v=4" width="100px;"/><br /><sub>Alexey Pronevich</sub>](https://github.com/pronevich)<br />[📖](https://github.com/satya164/linara/commits?author=pronevich "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/18573330?v=4" width="100px;"/><br /><sub>Wojtek Szafraniec</sub>](https://github.com/wojteg1337)<br />[💻](https://github.com/satya164/linara/commits?author=wojteg1337 "Code") | [<img src="https://avatars1.githubusercontent.com/u/1854763?v=4" width="100px;"/><br /><sub>Tushar Sonawane</sub>](https://twitter.com/tushkiz)<br />[📖](https://github.com/satya164/linara/commits?author=Tushkiz "Documentation") [💡](#example-Tushkiz "Examples") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<img src="https://avatars2.githubusercontent.com/u/774577?v=4" width="100px;"/><br /><sub>Ferran Negre</sub>](http://twitter.com/ferrannp)<br />[📖](https://github.com/satya164/linara/commits?author=ferrannp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/8135252?v=4" width="100px;"/><br /><sub>Jakub Beneš</sub>](https://jukben.cz)<br />[💻](https://github.com/satya164/linara/commits?author=jukben "Code") [📖](https://github.com/satya164/linara/commits?author=jukben "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/13413409?v=4" width="100px;"/><br /><sub>Oscar Busk</sub>](https://github.com/oBusk)<br />[🐛](https://github.com/satya164/linara/issues?q=author%3AoBusk "Bug reports") [💻](https://github.com/satya164/linara/commits?author=oBusk "Code") | [<img src="https://avatars3.githubusercontent.com/u/18584155?v=4" width="100px;"/><br /><sub>Dawid</sub>](https://github.com/Trancever)<br />[💻](https://github.com/satya164/linara/commits?author=Trancever "Code") [📖](https://github.com/satya164/linara/commits?author=Trancever "Documentation") |
| [<img src="https://avatars2.githubusercontent.com/u/17573635?v=4" width="100px;"/><br /><sub>Paweł Trysła</sub>](https://twitter.com/_zamotany)<br />[💻](https://github.com/satya164/linara/commits?author=zamotany "Code") [📖](https://github.com/satya164/linara/commits?author=zamotany "Documentation") [🤔](#ideas-zamotany "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/1174278?v=4" width="100px;"/><br /><sub>Satyajit Sahoo</sub>](https://medium.com/@satya164)<br />[💻](https://github.com/satya164/linara/commits?author=satya164 "Code") [🤔](#ideas-satya164 "Ideas, Planning, & Feedback") | [<img src="https://avatars2.githubusercontent.com/u/5106466?v=4" width="100px;"/><br /><sub>Michał Pierzchała</sub>](https://github.com/thymikee)<br />[💻](https://github.com/satya164/linara/commits?author=thymikee "Code") [📖](https://github.com/satya164/linara/commits?author=thymikee "Documentation") [🤔](#ideas-thymikee "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/1909761?v=4" width="100px;"/><br /><sub>Lucas</sub>](https://lcs.sh)<br />[📖](https://github.com/satya164/linara/commits?author=AgtLucas "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/680439?v=4" width="100px;"/><br /><sub>Alexey Pronevich</sub>](https://github.com/pronevich)<br />[📖](https://github.com/satya164/linara/commits?author=pronevich "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/18573330?v=4" width="100px;"/><br /><sub>Wojtek Szafraniec</sub>](https://github.com/wojteg1337)<br />[💻](https://github.com/satya164/linara/commits?author=wojteg1337 "Code") | [<img src="https://avatars1.githubusercontent.com/u/1854763?v=4" width="100px;"/><br /><sub>Tushar Sonawane</sub>](https://twitter.com/tushkiz)<br />[📖](https://github.com/satya164/linara/commits?author=Tushkiz "Documentation") [💡](#example-Tushkiz "Examples") |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| [<img src="https://avatars2.githubusercontent.com/u/774577?v=4" width="100px;"/><br /><sub>Ferran Negre</sub>](http://twitter.com/ferrannp)<br />[📖](https://github.com/satya164/linara/commits?author=ferrannp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/8135252?v=4" width="100px;"/><br /><sub>Jakub Beneš</sub>](https://jukben.cz)<br />[💻](https://github.com/satya164/linara/commits?author=jukben "Code") [📖](https://github.com/satya164/linara/commits?author=jukben "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/13413409?v=4" width="100px;"/><br /><sub>Oscar Busk</sub>](https://github.com/oBusk)<br />[🐛](https://github.com/satya164/linara/issues?q=author%3AoBusk "Bug reports") [💻](https://github.com/satya164/linara/commits?author=oBusk "Code") | [<img src="https://avatars3.githubusercontent.com/u/18584155?v=4" width="100px;"/><br /><sub>Dawid</sub>](https://github.com/Trancever)<br />[💻](https://github.com/satya164/linara/commits?author=Trancever "Code") [📖](https://github.com/satya164/linara/commits?author=Trancever "Documentation") |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
Expand Down
5 changes: 5 additions & 0 deletions bin/linaria.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

/* eslint-disable import/no-unresolved */

module.exports = require('../lib/cli');
34 changes: 34 additions & 0 deletions docs/CLI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# CLI

Linaria CLI allows you to extract CSS from your source files using a command line.

### Usage

```bash
yarn linaria [options] <file1> [<fileN>...]
```

Option `-o, --out-dir <dir>` __is always required__.

You can also use glob for specifying files to process:

```bash
yarn linaria -o styles src/component/**/*.js
# or multiple globs
yarn linaria -o styles src/component/**/*.js src/screens/**/*.js
```

CLI supports adding a require statement for generated CSS file automatically:

```bash
yarn linaria -o out-dir --source-root src --insert-css-requires dist src/**/*.js
```

where `source-root` is directory with source JS files and `insert-css-requires` has directory with transpiled/compiled JS files.

### Options

* `-o, --out-dir <dir>` (__required__) - Output directory for the extracted CSS files
* `-s, --source-maps` - Generate source maps for the CSS files
* `-r, --source-root <dir>` - Directory containing the source JS files
* `-i, --insert-css-requires <dir>` - Directory containing JS files to insert require statements for the CSS files (__works only if `-r, --source-root` is provided__)
3 changes: 3 additions & 0 deletions node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable import/no-unresolved */

module.exports = require('./lib/node');
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.0.0-beta.4",
"description": "Blazing fast zero-runtime CSS in JS library",
"main": "lib/index.js",
"bin": "./bin/linaria.js",
"files": [
"lib/",
"react.js",
Expand Down Expand Up @@ -40,6 +41,7 @@
"add-contributor": "all-contributors add",
"prebuild": "del lib",
"build": "babel src --out-dir lib --ignore '**/__tests__/**,**/__integration-tests__/**,**/__fixtures__/**' --source-maps && flow-copy-source -i '{**/__tests__/**,**/__integration-tests__/**,**/__fixtures__/**}' src lib",
"watch": "babel src --out-dir lib --ignore '**/__tests__/**,**/__integration-tests__/**,**/__fixtures__/**' --source-maps --watch",
"prepare": "yarn build",
"release": "release-it",
"now-build": "yarn --cwd website install && yarn --cwd website build",
Expand All @@ -60,7 +62,6 @@
"babel-core": "^7.0.0-bridge.0",
"codecov": "^3.1.0",
"conventional-changelog-cli": "^2.0.5",
"dedent": "^0.7.0",
"del-cli": "^1.1.0",
"dtslint": "^0.3.0",
"eslint": "^5.7.0",
Expand All @@ -82,14 +83,17 @@
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-modules-commonjs": "^7.1.0",
"@babel/register": "^7.0.0",
"dedent": "^0.7.0",
"glob": "^7.1.3",
"cosmiconfig": "^5.0.7",
"loader-utils": "^1.1.0",
"mkdirp": "^0.5.1",
"postcss": "^7.0.5",
"react-is": "^16.5.2",
"postcss": "^7.0.2",
"react-is": "^16.5.1",
"rollup-pluginutils": "^2.3.3",
"source-map": "^0.7.3",
"stylis": "^3.5.3"
"stylis": "^3.5.4",
"yargs": "^12.0.5"
},
"resolutions": {
"**/babel-core": "7.0.0-bridge.0"
Expand Down
132 changes: 132 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env node

/* @flow */

const path = require('path');
const fs = require('fs');
const mkdirp = require('mkdirp');
const glob = require('glob');
const yargs = require('yargs');
const transform = require('./transform');

const { argv } = yargs
.usage('Usage: $0 [options] <files ...>')
.option('out-dir', {
alias: 'o',
type: 'string',
description: 'Output directory for the extracted CSS files',
demandOption: true,
requiresArg: true,
})
.option('source-maps', {
alias: 's',
type: 'boolean',
description: 'Generate source maps for the CSS files',
default: false,
})
.option('source-root', {
alias: 'r',
type: 'string',
description: 'Directory containing the source JS files',
requiresArg: true,
})
.option('insert-css-requires', {
alias: 'i',
type: 'string',
description:
'Directory containing JS files to insert require statements for the CSS files',
requiresArg: true,
})
.implies('insert-css-requires', 'source-root')
.alias('help', 'h')
.alias('version', 'v')
.strict();

processFiles(argv._, {
outDir: argv['out-dir'],
sourceMaps: argv['source-maps'],
sourceRoot: argv['source-root'],
insertCssRequires: argv['insert-css-requires'],
});

type Options = {
outDir: string,
sourceMaps?: boolean,
sourceRoot?: string,
insertCssRequires?: string,
};

function processFiles(files: string[], options: Options) {
let count = 0;

const resolvedFiles = files.reduce(
(acc, pattern) => [...acc, ...glob.sync(pattern, { absolute: true })],
[]
);

resolvedFiles.forEach(filename => {
const outputFilename = resolveOutputFilename(filename, options.outDir);

const { cssText, sourceMap, cssSourceMapText } = transform(
fs.readFileSync(filename).toString(),
{
filename,
outputFilename,
pluginOptions: {},
}
);

if (cssText) {
mkdirp.sync(path.dirname(outputFilename));

const cssContent =
options.sourceMaps && sourceMap
? `${cssText}\n/*# sourceMappingURL=${outputFilename}.map */`
: cssText;

fs.writeFileSync(outputFilename, cssContent);

if (
options.sourceMaps &&
sourceMap &&
typeof cssSourceMapText !== 'undefined'
) {
fs.writeFileSync(`${outputFilename}.map`, cssSourceMapText);
}

if (options.insertCssRequires && options.sourceRoot) {
const inputFilename = path.resolve(
options.insertCssRequires,
path.relative(options.sourceRoot, filename)
);

const requireStatement = `\nrequire('${path.relative(
path.dirname(inputFilename),
outputFilename
)}');`;

const inputContent = fs.readFileSync(inputFilename, 'utf-8');

if (!inputContent.trim().endsWith(requireStatement)) {
fs.writeFileSync(
inputFilename,
`${inputContent}\n${requireStatement}`
);
}
}

count++;
}
});

console.log(`Successfully extracted ${count} CSS files.`);
}

function resolveOutputFilename(filename: string, outDir: string) {
const folderStructure = path.relative(process.cwd(), path.dirname(filename));
const outputBasename = path
.basename(filename)
.replace(path.extname(filename), '.css');

return path.join(outDir, folderStructure, outputBasename);
}
20 changes: 11 additions & 9 deletions src/loader.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* @flow */

const fs = require('fs');
const path = require('path');
const mkdirp = require('mkdirp');
/* $FlowFixMe */
const Module = require('module');
const loaderUtils = require('loader-utils');
const transform = require('./transform');

module.exports = function loader(content, inputSourceMap) {
module.exports = function loader(content: string, inputSourceMap: ?Object) {
const { sourceMap, cacheDirectory = '.linaria-cache', ...rest } =
loaderUtils.getOptions(this) || {};

Expand All @@ -19,20 +22,19 @@ module.exports = function loader(content, inputSourceMap) {
)
);

const result = transform(
this.resourcePath,
content,
rest,
inputSourceMap,
outputFilename
);
const result = transform(content, {
filename: this.resourcePath,
inputSourceMap: inputSourceMap != null ? inputSourceMap : undefined,
outputFilename,
pluginOptions: rest,
});

if (result.cssText) {
let { cssText } = result;

if (sourceMap) {
cssText += `/*# sourceMappingURL=data:application/json;base64,${Buffer.from(
result.cssSourceMapText
result.cssSourceMapText || ''
).toString('base64')}*/`;
}

Expand Down
3 changes: 3 additions & 0 deletions src/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* @flow */

module.exports.transform = require('./transform');
5 changes: 4 additions & 1 deletion src/rollup.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ module.exports = function linaria({
transform(code: string, id: string) {
if (!filter(id)) return;

const result = transform(id, code, rest);
const result = transform(code, {
filename: id,
pluginOptions: rest,
});

if (!result.cssText) return;

Expand Down
6 changes: 3 additions & 3 deletions src/stylelint/preprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ function preprocessor() {

return {
code(input: string, filename: string) {
/* eslint-disable prefer-destructuring */

let result;

try {
result = transform(filename, input);
result = transform(input, {
filename,
});
} catch (e) {
// Ignore parse errors
return '';
Expand Down
Loading

0 comments on commit 8ace1f3

Please sign in to comment.