UNPKG

18.1 kBMarkdownView Raw
1<div align="center">
2 <a href="https://github.com/webpack/webpack">
3 <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
4 </a>
5</div>
6
7[![npm][npm]][npm-url]
8[![node][node]][node-url]
9[![tests][tests]][tests-url]
10[![cover][cover]][cover-url]
11[![discussion][discussion]][discussion-url]
12[![size][size]][size-url]
13
14# stylus-loader
15
16A Stylus loader for webpack. Compiles Styl to CSS.
17
18## Getting Started
19
20To begin, you'll need to install `stylus` and `stylus-loader`:
21
22```console
23npm install stylus stylus-loader --save-dev
24```
25
26or
27
28```console
29yarn add -D stylus stylus-loader
30```
31
32or
33
34```console
35pnpm add -D stylus stylus-loader
36```
37
38Then add the loader to your `webpack` config. For example:
39
40**webpack.config.js**
41
42```js
43module.exports = {
44 module: {
45 rules: [
46 {
47 test: /\.styl$/,
48 loader: "stylus-loader", // compiles Styl to CSS
49 },
50 ],
51 },
52};
53```
54
55And run `webpack` via your preferred method.
56
57## Options
58
59- **[`stylusOptions`](#stylusOptions)**
60- **[`sourceMap`](#sourcemap)**
61- **[`webpackImporter`](#webpackimporter)**
62- **[`additionalData`](#additionalData)**
63- **[`implementation`](#implementation)**
64
65### `stylusOptions`
66
67Type:
68
69```ts
70type stylusOptions =
71 | {
72 use: Array<string | Function>;
73 include: string;
74 import: string;
75 define: Array;
76 includeCSS: false;
77 resolveURL: boolean | Object;
78 lineNumbers: boolean;
79 hoistAtrules: boolean;
80 compress: boolean;
81 }
82 | (loaderContext: LoaderContext) => Array<string>;
83```
84
85Default: `{}`
86
87You can pass any Stylus specific options to the `stylus-loader` through the `stylusOptions` property in the [loader options](https://webpack.js.org/configuration/module/#rule-options-rule-query).
88See the [Stylus documentation](https://stylus-lang.com/docs/js.html).
89Options in dash-case should use camelCase.
90
91#### `object`
92
93Use an object to pass options through to Stylus.
94
95**webpack.config.js**
96
97```js
98module.exports = {
99 module: {
100 rules: [
101 {
102 test: /\.styl$/,
103 use: [
104 {
105 loader: "style-loader",
106 },
107 {
108 loader: "css-loader",
109 },
110 {
111 loader: "stylus-loader",
112 options: {
113 stylusOptions: {
114 /**
115 * Specify Stylus plugins to use. Plugins may be passed as
116 * strings instead of importing them in your Webpack config.
117 *
118 * @type {(string|Function)[]}
119 * @default []
120 */
121 use: ["nib"],
122
123 /**
124 * Add path(s) to the import lookup paths.
125 *
126 * @type {string[]}
127 * @default []
128 */
129 include: [path.join(__dirname, "src/styl/config")],
130
131 /**
132 * Import the specified Stylus files/paths.
133 *
134 * @type {string[]}
135 * @default []
136 */
137 import: ["nib", path.join(__dirname, "src/styl/mixins")],
138
139 /**
140 * Define Stylus variables or functions.
141 *
142 * @type {Array|Object}
143 * @default {}
144 */
145 // Array is the recommended syntax: [key, value, raw]
146 define: [
147 ["$development", process.env.NODE_ENV === "development"],
148 ["rawVar", 42, true],
149 ],
150 // Object is deprecated syntax (there is no possibility to specify "raw')
151 // define: {
152 // $development: process.env.NODE_ENV === 'development',
153 // rawVar: 42,
154 // },
155
156 /**
157 * Include regular CSS on @import.
158 *
159 * @type {boolean}
160 * @default false
161 */
162 includeCSS: false,
163
164 /**
165 * Resolve relative url()'s inside imported files.
166 *
167 * @see https://stylus-lang.com/docs/js.html#stylusresolveroptions
168 *
169 * @type {boolean|Object}
170 * @default { nocheck: true }
171 */
172 resolveURL: true,
173 // resolveURL: { nocheck: true },
174
175 /**
176 * Emits comments in the generated CSS indicating the corresponding Stylus line.
177 *
178 * @see https://stylus-lang.com/docs/executable.html
179 *
180 * @type {boolean}
181 * @default false
182 */
183 lineNumbers: true,
184
185 /**
186 * Move @import and @charset to the top.
187 *
188 * @see https://stylus-lang.com/docs/executable.html
189 *
190 * @type {boolean}
191 * @default false
192 */
193 hoistAtrules: true,
194
195 /**
196 * Compress CSS output.
197 * In the "production" mode is `true` by default
198 *
199 * @see https://stylus-lang.com/docs/executable.html
200 *
201 * @type {boolean}
202 * @default false
203 */
204 compress: true,
205 },
206 },
207 },
208 ],
209 },
210 ],
211 },
212};
213```
214
215#### `function`
216
217Allows setting the options passed through to Stylus based off of the loader context.
218
219```js
220module.exports = {
221 module: {
222 rules: [
223 {
224 test: /\.styl/,
225 use: [
226 "style-loader",
227 "css-loader",
228 {
229 loader: "stylus-loader",
230 options: {
231 stylusOptions: (loaderContext) => {
232 // More information about available properties https://webpack.js.org/api/loaders/
233 const { resourcePath, rootContext } = loaderContext;
234 const relativePath = path.relative(rootContext, resourcePath);
235
236 if (relativePath === "styles/foo.styl") {
237 return {
238 paths: ["absolute/path/c", "absolute/path/d"],
239 };
240 }
241
242 return {
243 paths: ["absolute/path/a", "absolute/path/b"],
244 };
245 },
246 },
247 },
248 ],
249 },
250 ],
251 },
252};
253```
254
255### `sourceMap`
256
257Type:
258
259```ts
260type sourceMap = boolean;
261```
262
263**webpack.config.js**
264
265```js
266module.exports = {
267 module: {
268 rules: [
269 {
270 test: /\.styl$/i,
271 use: [
272 "style-loader",
273 {
274 loader: "css-loader",
275 options: {
276 sourceMap: true,
277 },
278 },
279 {
280 loader: "stylus-loader",
281 options: {
282 sourceMap: true,
283 },
284 },
285 ],
286 },
287 ],
288 },
289};
290```
291
292### `webpackImporter`
293
294Type:
295
296```ts
297type webpackImporter = boolean;
298```
299
300Default: `true`
301
302Enables/Disables the default Webpack importer.
303
304This can improve performance in some cases.
305Use it with caution because aliases and `@import` at-rules starting with `~` will not work.
306
307**webpack.config.js**
308
309```js
310module.exports = {
311 module: {
312 rules: [
313 {
314 test: /\.styl/i,
315 use: [
316 "style-loader",
317 "css-loader",
318 {
319 loader: "stylus-loader",
320 options: {
321 webpackImporter: false,
322 },
323 },
324 ],
325 },
326 ],
327 },
328};
329```
330
331### `additionalData`
332
333Type:
334
335```ts
336type additionalData =
337 | string
338 | (
339 content: string | Buffer,
340 loaderContext: LoaderContext,
341 meta: any
342 ) => string;
343```
344
345Default: `undefined`
346
347Prepends `Stylus` code before the actual entry file.
348In this case, the `stylus-loader` will not override the source but just **prepend** the entry's content.
349
350This is especially useful when some of your Stylus variables depend on the environment:
351
352> **Note**
353>
354> Since you're injecting code, this will break the source mappings in your entry file. Often there's a simpler solution than this, like multiple Stylus entry files.
355
356#### `string`
357
358```js
359module.exports = {
360 module: {
361 rules: [
362 {
363 test: /\.styl/,
364 use: [
365 "style-loader",
366 "css-loader",
367 {
368 loader: "stylus-loader",
369 options: {
370 additionalData: `@env: ${process.env.NODE_ENV};`,
371 },
372 },
373 ],
374 },
375 ],
376 },
377};
378```
379
380#### `function`
381
382##### Sync
383
384```js
385module.exports = {
386 module: {
387 rules: [
388 {
389 test: /\.styl/,
390 use: [
391 "style-loader",
392 "css-loader",
393 {
394 loader: "stylus-loader",
395 options: {
396 additionalData: (content, loaderContext) => {
397 // More information about available properties https://webpack.js.org/api/loaders/
398 const { resourcePath, rootContext } = loaderContext;
399 const relativePath = path.relative(rootContext, resourcePath);
400
401 if (relativePath === "styles/foo.styl") {
402 return "value = 100px" + content;
403 }
404
405 return "value 200px" + content;
406 },
407 },
408 },
409 ],
410 },
411 ],
412 },
413};
414```
415
416##### Async
417
418```js
419module.exports = {
420 module: {
421 rules: [
422 {
423 test: /\.styl/,
424 use: [
425 "style-loader",
426 "css-loader",
427 {
428 loader: "stylus-loader",
429 options: {
430 additionalData: async (content, loaderContext) => {
431 // More information about available properties https://webpack.js.org/api/loaders/
432 const { resourcePath, rootContext } = loaderContext;
433 const relativePath = path.relative(rootContext, resourcePath);
434
435 if (relativePath === "styles/foo.styl") {
436 return "value = 100px" + content;
437 }
438
439 return "value 200px" + content;
440 },
441 },
442 },
443 ],
444 },
445 ],
446 },
447};
448```
449
450### `implementation`
451
452Type:
453
454```ts
455type implementation = Function | string;
456```
457
458The special `implementation` option determines which implementation of Stylus to use. Overrides the locally installed `peerDependency` version of `stylus`.
459
460#### `function`
461
462**webpack.config.js**
463
464```js
465module.exports = {
466 module: {
467 rules: [
468 {
469 test: /\.styl/i,
470 use: [
471 "style-loader",
472 "css-loader",
473 {
474 loader: "stylus-loader",
475 options: {
476 implementation: require("stylus"),
477 },
478 },
479 ],
480 },
481 ],
482 },
483};
484```
485
486#### `string`
487
488**webpack.config.js**
489
490```js
491module.exports = {
492 module: {
493 rules: [
494 {
495 test: /\.styl/i,
496 use: [
497 "style-loader",
498 "css-loader",
499 {
500 loader: "stylus-loader",
501 options: {
502 implementation: require.resolve("stylus"),
503 },
504 },
505 ],
506 },
507 ],
508 },
509};
510```
511
512## Examples
513
514### Normal usage
515
516Chain the `stylus-loader` with the [`css-loader`](https://github.com/webpack-contrib/css-loader) and the [`style-loader`](https://github.com/webpack-contrib/style-loader) to immediately apply all styles to the DOM.
517
518**webpack.config.js**
519
520```js
521module.exports = {
522 module: {
523 rules: [
524 {
525 test: /\.styl$/,
526 use: [
527 {
528 loader: "style-loader", // creates style nodes from JS strings
529 },
530 {
531 loader: "css-loader", // translates CSS into CommonJS
532 },
533 {
534 loader: "stylus-loader", // compiles Stylus to CSS
535 },
536 ],
537 },
538 ],
539 },
540};
541```
542
543### Source maps
544
545To enable sourcemaps for CSS, you'll need to pass the `sourceMap` property in the loader's options. If this is not passed, the loader will respect the setting for webpack source maps, set in `devtool`.
546
547**webpack.config.js**
548
549```javascript
550module.exports = {
551 devtool: "source-map", // any "source-map"-like devtool is possible
552 module: {
553 rules: [
554 {
555 test: /\.styl$/,
556 use: [
557 "style-loader",
558 {
559 loader: "css-loader",
560 options: {
561 sourceMap: true,
562 },
563 },
564 {
565 loader: "stylus-loader",
566 options: {
567 sourceMap: true,
568 },
569 },
570 ],
571 },
572 ],
573 },
574};
575```
576
577### Using nib with stylus
578
579**webpack.config.js**
580
581```js
582module.exports = {
583 module: {
584 rules: [
585 {
586 test: /\.styl$/,
587 use: [
588 {
589 loader: "style-loader", // creates style nodes from JS strings
590 },
591 {
592 loader: "css-loader", // translates CSS into CommonJS
593 },
594 {
595 loader: "stylus-loader", // compiles Stylus to CSS
596 options: {
597 stylusOptions: {
598 use: [require("nib")()],
599 import: ["nib"],
600 },
601 },
602 },
603 ],
604 },
605 ],
606 },
607};
608```
609
610### Import JSON files
611
612Stylus does not provide resolving capabilities in the `json` function.
613Therefore webpack resolver does not work for `.json` files.
614Use [`stylus resolver`](#stylus-resolver).
615
616**index.styl**
617
618```styl
619// Suppose the file is located here `node_modules/vars/vars.json`
620json('vars.json')
621
622@media queries-small
623 body
624 display nope
625
626```
627
628**webpack.config.js**
629
630```js
631module.exports = {
632 module: {
633 rules: [
634 {
635 test: /\.styl$/,
636 use: [
637 "style-loader",
638 "css-loader",
639 {
640 loader: "stylus-loader",
641 options: {
642 stylusOptions: {
643 // Specify the path. where to find files
644 paths: ["node_modules/vars"],
645 },
646 },
647 },
648 ],
649 },
650 ],
651 },
652};
653```
654
655### In production
656
657Usually, it's recommended to extract the style sheets into a dedicated file in production using the [MiniCssExtractPlugin](https://github.com/webpack-contrib/mini-css-extract-plugin). This way your styles are not dependent on JavaScript.
658
659### webpack resolver
660
661Webpack provides an [advanced mechanism to resolve files](https://webpack.js.org/configuration/resolve/).
662The `stylus-loader` applies the webpack resolver when processing queries.
663Thus you can import your Stylus modules from `node_modules`.
664
665```styl
666@import 'bootstrap-styl/bootstrap/index.styl';
667```
668
669Using `~` is deprecated and can be removed from your code (**we recommend it**), but we still support it for historical reasons.
670Why you can removed it? The loader will first try to resolve `@import`/`@require` as relative, if it cannot be resolved, the loader will try to resolve `@import`/`@require` inside [`node_modules`](https://webpack.js.org/configuration/resolve/#resolve-modules).
671Just prepend them with a `~` which tells webpack to look up the [`modules`](https://webpack.js.org/configuration/resolve/#resolve-modules).
672
673```styl
674@import "~bootstrap-styl/bootstrap/index.styl";
675```
676
677It's important to only prepend it with `~`, because `~/` resolves to the home-directory.
678Webpack needs to distinguish between `bootstrap` and `~bootstrap`, because CSS and Styl files have no special syntax for importing relative files.
679Writing `@import "file"` is the same as `@import "./file";`
680
681### Stylus resolver
682
683If you specify the `paths` option, modules will be searched in the given `paths`.
684This is Stylus default behavior.
685
686**webpack.config.js**
687
688```js
689module.exports = {
690 module: {
691 rules: [
692 {
693 test: /\.styl/,
694 use: [
695 {
696 loader: "style-loader",
697 },
698 {
699 loader: "css-loader",
700 },
701 {
702 loader: "stylus-loader",
703 options: {
704 stylusOptions: {
705 paths: [path.resolve(__dirname, "node_modules")],
706 },
707 },
708 },
709 ],
710 },
711 ],
712 },
713};
714```
715
716### Extracting style sheets
717
718Bundling CSS with webpack has some nice advantages like referencing images and fonts with hashed urls or [hot module replacement](https://webpack.js.org/concepts/hot-module-replacement/) in development. In production, on the other hand, it's not a good idea to apply your style sheets depending on JS execution. Rendering may be delayed or even a [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) might be visible. Thus it's often still better to have them as separate files in your final production build.
719
720There are two possibilities to extract a style sheet from the bundle:
721
722- [`extract-loader`](https://github.com/peerigon/extract-loader) (simpler, but specialized on the css-loader's output)
723- [MiniCssExtractPlugin](https://github.com/webpack-contrib/mini-css-extract-plugin) (more complex, but works in all use-cases)
724
725## Contributing
726
727Please take a moment to read our contributing guidelines if you haven't yet done so.
728
729[CONTRIBUTING](./.github/CONTRIBUTING.md)
730
731## License
732
733[MIT](./LICENSE)
734
735[npm]: https://img.shields.io/npm/v/stylus-loader.svg
736[npm-url]: https://npmjs.com/package/stylus-loader
737[node]: https://img.shields.io/node/v/stylus-loader.svg
738[node-url]: https://nodejs.org
739[tests]: https://github.com/webpack-contrib/stylus-loader/workflows/stylus-loader/badge.svg
740[tests-url]: https://github.com/webpack-contrib/stylus-loader/actions
741[cover]: https://codecov.io/gh/webpack-contrib/stylus-loader/branch/master/graph/badge.svg
742[cover-url]: https://codecov.io/gh/webpack-contrib/stylus-loader
743[discussion]: https://img.shields.io/github/discussions/webpack/webpack
744[discussion-url]: https://github.com/webpack/webpack/discussions
745[size]: https://packagephobia.now.sh/badge?p=stylus-loader
746[size-url]: https://packagephobia.now.sh/result?p=stylus-loader