UNPKG

8.48 kBMarkdownView Raw
1# jsxstyle-loader
2
3`jsxstyle-loader` is a webpack loader that extracts [**static style props**](#what-are-static-style-props) from jsxstyle components into a separate CSS file.
4
5Don’t know what jsxstyle is? Check out the [jsxstyle README][] for more information.
6
7## Getting Started
8
91. Add a new rule object for `jsxstyle-loader` to your webpack config, _below_ any other JS loaders.
10
11 > `jsxstyle-loader` relies on untranspiled JSX to be present in order to extract styles. Since webpack loaders run from right to left and bottom to top, `jsxstyle-loader` should be placed at the end of your list of JS loaders.
12
132. Add `jsxstyle-loader`’s companion plugin to the `plugins` section of your webpack config.
14
153. Ensure your webpack config contains a loader that handles `.css` files.
16
17When you’re done, the relevant parts of your webpack config should look like this:
18
19```js
20const JsxstyleLoaderPlugin = require('jsxstyle-loader/plugin');
21
22module.exports = {
23 // ...
24 plugins: [new JsxstyleLoaderPlugin()],
25 // ...
26 module: {
27 rules: [
28 // ...
29 {
30 test: /\.js$/,
31 use: [
32 // any loaders that transpile JSX should go above jsxstyle-loader
33 {
34 loader: 'your-cool-js-loader',
35 },
36 // jsxstyle-loader goes at the end
37 {
38 loader: 'jsxstyle-loader',
39 },
40 ],
41 },
42 {
43 test: /\.css$/,
44 use: 'your-cool-css-loader',
45 },
46 // ...
47 ],
48 },
49};
50```
51
52## Loader Options
53
54### `styleGroups`
55
56By default, `jsxstyle-loader` will extract all static style props on a jsxstyle component into one class. This can lead to CSS classes that contain a lot of common style declarations. A good CSS minifier should help with this, but if you want a bit more control over how styles are grouped into CSS classes, you can provide an _array_ of CSS style objects. When `jsxstyle-loader` encounters a component that contains all styles in a style object, those styles will be extracted into a separate class name.
57
58For example, with the following loader config:
59
60```js
61{
62 loader: 'jsxstyle-loader',
63 options: {
64 styleGroups: [
65 {
66 display: 'block',
67 },
68 {
69 marginLeft: 15,
70 marginRight: 15,
71 },
72 ],
73 },
74}
75```
76
77...and a jsxstyle component that looks like this:
78
79```jsx
80import { Block } from 'jsxstyle';
81
82<Block backgroundColor="blue" marginLeft={15} marginRight={15} padding={20} />;
83```
84
85...the styles on this component will be extracted into three separate classes:
86
87```css
88._x0 {
89 display: block;
90}
91._x1 {
92 margin-left: 15px;
93 margin-right: 15px;
94}
95._x2 {
96 background-color: blue;
97 padding: 20px;
98}
99```
100
101Without the `styleGroups` parameter, all five style props would be extracted into one class.
102
103### `namedStyleGroups`
104
105The `namedStyleGroups` config option is just like the `styleGroups` config option, with one key difference: it is expected to be an _object_ of CSS style objects, not an array. The key of the CSS style object will be used as the class name if all props and values are present on a jsxstyle component.
106
107### `whitelistedModules`
108
109The `whitelistedModules` config option allows you to add modules to the evaluation context. For example, with the following loader config, any prop on a jsxstyle component that references a value from `./LayoutConstants.js` will be assumed to be evaluatable:
110
111```js
112{
113 loader: 'jsxstyle-loader',
114 options: {
115 whitelistedModules: [
116 require.resolve('./LayoutConstants'),
117 ],
118 },
119}
120```
121
122> **Note**: the modules you specify as `whitelistedModules` _will not be transpiled_, so make sure they’re in a format that’s compatible with your version of node.
123
124### `parserPlugins`
125
126`jsxstyle-loader` uses `babylon` to parse javascript into an AST. By default, `jsxstyle-loader` is preconfigured with most of `babylon`’s plugins enabled, but if you need to enable additional plugins, you can specify an array of plugins with the `parserPlugins` option.
127
128You can see a list of all available plugins in [the `babylon` README][babylon plugins].
129
130### `classNameFormat`
131
132Out of the box, `jsxstyle-loader` will use a _non-deterministic_ class naming scheme. Because webpack’s module iteration order is not guaranteed, class names will differ slightly between builds of the same code. If you need class names to remain the same each time the same code is bundled, set the `classNameFormat` option to `hash` in your loader config. Class names will be generated using a content-based hash.
133
134### `liteMode`
135
136```jsx
137// look ma, no jsxstyle import
138<block color="red">This text will be red</block>
139```
140
141Instead of importing components from `jsxstyle` or `jsxstyle/preact`, don’t import _anything_ and just use the dash-case version of the component name as if it’s a valid DOM element. When `jsxstyle-loader` encounters one of these dash-case elements, it’ll treat it like the PascalCased equivalent component imported from `jsxstyle` or `jsxstyle/preact`.
142
143To enable this feature, set `liteMode` in your loader options to either `'react'` or `'preact'`.
144
145## FAQs
146
147### Can I use `jsxstyle-loader` with Flow?
148
149Yes! Flow parsing is automatically enabled for any non-Typescript files.
150
151### Can I use `jsxstyle-loader` with Typescript?
152
153Yes! Take a look at [the TypeScript example][ts example] and [issue #82][issue 82] for some context. You’ll need to make a few configuration changes:
154
1551. Set `jsx` to `preserve` in the `compilerOptions` section of your `tsconfig.json` file.
1562. Ensure `jsxstyle-loader` runs _after_ `ts-loader`. Webpack loaders run from bottom to top, to `jsxstyle-loader` needs to be placed _before_ `ts-loader` in your webpack config.
1573. Add a loader that transpiles JSX, since `ts-loader` is now set to preserve JSX.
158
159### It’s not working 😩
160
1611. Make sure the loader object `test` regex matches JS files that use jsxstyle.
1622. `jsxstyle-loader` relies on JSX still being around, so make sure it runs _before_ `babel-loader` does its thing.
1633. `jsxstyle-loader` only supports destructured `require`/`import` syntax:
164
165 ```jsx
166 // Cool!
167 import { Block } from 'jsxstyle';
168 <Block />;
169
170 // Neat!
171 const { Block } = require('jsxstyle');
172 <Block />;
173
174 // Nope :(
175 const Block = require('jsxstyle').Block;
176 <Block />;
177 ```
178
179### What are “static style props”?
180
181Simply put, static style props are props whose values can be evaluated at build time. By default, this consists of any literal type (`string`, `number`, `null`) as well as any variables provided to the evaluation context. The evaluation context is derived from the prop’s current scope.
182
183For example, the `fontSize` prop in the following component will be marked as evaluatable and will be extracted as `42`:
184
185```jsx
186import { Block } from 'jsxstyle';
187
188const bestNumber = 42;
189<Block fontSize={bestNumber}>hello</Block>;
190```
191
192Any modules marked as whitelisted with the [`whitelistedModules`](#whitelistedmodules) config option will also be added to the evaluation context.
193
194If the value of a style prop is a ternary and both sides can be evaluated, the prop will be extracted and the ternary condition will be moved to the `className`.
195
196If the value of a prop is a simple logical expression with the `&&` operator, it will be converted to a ternary with a null alternate.
197
198### Inline styles… _are bad_.
199
200See [the jsxstyle FAQs][jsxstyle faqs].
201
202### Does it work with hot reloading?
203
204It sure does, but using it in development will only cause confusion, since what you will see in the developer tools is the _transformed_ JS. `jsxstyle-loader` is a _production_ optimisation.
205
206### Any caveats?
207
208One big one: CSS class names are not de-duplicated across components. Any CSS minifier that combines identical class names will handle deduplication.
209
210## Contributing
211
212Got an idea for `jsxstyle-loader`? Did you encounter a bug? [Open an issue][new issue] and let’s talk it through. [PRs welcome too][pr]!
213
214[jsxstyle readme]: https://github.com/smyte/jsxstyle/tree/master/packages/jsxstyle#readme
215[jsxstyle faqs]: https://github.com/smyte/jsxstyle/tree/master/packages/jsxstyle#faqs
216[babylon plugins]: https://github.com/babel/babylon#plugins
217[new issue]: https://github.com/smyte/jsxstyle/issues/new
218[pr]: https://github.com/smyte/jsxstyle/pulls
219[ts example]: https://github.com/smyte/jsxstyle/tree/master/examples/jsxstyle-typescript-example
220[issue 82]: https://github.com/smyte/jsxstyle/issues/82#issuecomment-355141948