next-blurhash-previews 0.0.3-beta4 → 0.0.3-beta5

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,9 @@ import { fileURLToPath } from "url";
6
6
 
7
7
  import { reporter } from "vfile-reporter";
8
8
  import { remark } from "remark";
9
+ import remarkFrontmatter from "remark-frontmatter";
10
+ import remarkStringify from "remark-stringify";
11
+
9
12
  import glob from "glob";
10
13
  import colors from "colors";
11
14
 
@@ -37,6 +40,10 @@ async function runFile(file) {
37
40
  return new Promise(res => {
38
41
  remark()
39
42
  .use(blurhashPlugin(publicPath))
43
+ .use(remarkFrontmatter)
44
+ .use(remarkStringify, {
45
+ fences: true,
46
+ })
40
47
  .process(buffer)
41
48
  .then(outputFile => {
42
49
  fs.writeFileSync(file, outputFile.toString());
@@ -1,33 +1,303 @@
1
- <blurhash-image
2
- url="./img1.png"
3
- preview='{"blurhash":"U8SF;LD*%gofIUM|xuRj~qaeM{RjxtoIWBWC","w":364,"h":196}'
4
- >
5
- <img alt="A" src="./img1.png" slot="image" />
6
- <canvas width="364" height="196" slot="preview"></canvas>
7
- </blurhash-image>
8
-
9
- <some-component>
10
- <p>Hello</p>
11
- </some-component>
12
-
13
- Yo
14
-
15
- <blurhash-image
16
- url="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
17
- preview='{"blurhash":"U38|kkTJ01}A;{Or57;N01NG+?IW01rX^NAW","w":106,"h":160}'
18
- >
19
- <img
20
- alt="external image"
21
- src="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
22
- slot="image"
23
- />
24
- <canvas width="106" height="160" slot="preview"></canvas>
25
- </blurhash-image>
26
-
27
- <blurhash-image
28
- url="./img1.png"
29
- preview='{"blurhash":"U8SF;LD*%gofIUM|xuRj~qaeM{RjxtoIWBWC","w":364,"h":196}'
30
- >
31
- <img alt="" src="./img1.png" slot="image" />
32
- <canvas width="364" height="196" slot="preview"></canvas>
33
- </blurhash-image>
1
+ ---
2
+ title: Loading css, css-modules, and Sass with webpack
3
+ date: "2019-05-13T10:00:00.000Z"
4
+ description: An introduction to loading css with webpack, and enabling css-modules, and SASS in the process
5
+ ---
6
+
7
+ The css ecosystem is immense and, at times, intimidating. This post will start at the beginning. We'll go over loading basic css with webpack, then move on to css modules, and wrap up with Sass. If you have some experience loading css in webpack-based web applications, some of this may be old news for you.
8
+
9
+ Note that while the code samples in this post use React, none of the concepts are specific to it in the least. Also, this post does _not_ cover css-in-js, for the simple reason that I haven't yet gotten around to diving into that ecosystem; I'm hoping by the time I do, it'll be a bit less crowded :)
10
+
11
+ ## Starting at the beginning: basic css loading
12
+
13
+ Let's say we're rendering this component.
14
+
15
+ ```jsx
16
+ const Component = () => (
17
+ <div className="pane">
18
+ <span>Pane Content</span>
19
+ <ul className="list">
20
+ <li className="list-item">Item 1</li>
21
+ <li className="list-item">Item 2</li>
22
+ <li className="list-item">Item 3</li>
23
+ </ul>
24
+ </div>
25
+ );
26
+ ```
27
+
28
+ Without accompanying styles, it'll look something like this.
29
+
30
+ ![Unstyled Component](/css-modules/unstyledComp.png)
31
+
32
+ Let's add some basic styling. Let's start simple, and have the JS module this component sits in import a css file, with standard, global styling rules. The import will look like this
33
+
34
+ ```javascript
35
+ import "./styles.css";
36
+ ```
37
+
38
+ Let's create that file, and add some purposefully ugly styles
39
+
40
+ ```css
41
+ .pane {
42
+ background-color: green;
43
+ max-width: 300px;
44
+ }
45
+
46
+ .pane span {
47
+ color: purple;
48
+ }
49
+
50
+ .list {
51
+ margin-left: 20px;
52
+ }
53
+
54
+ .list-item {
55
+ list-style-type: lower-greek;
56
+ }
57
+ ```
58
+
59
+ As we have it, this code leads to the following webpack error
60
+
61
+ ![Loading error](/css-modules/loadingError.png)
62
+
63
+ webpack only knows how to load standard JavaScript by default. To add other content, like css, we need to tell webpack how to handle it. Let's do that now. First, install the `mini-css-extract-plugin` and `css-loader` plugins, using your favorite package manager, in your favorite cli.
64
+
65
+ Now load the mini css extract plugin in your webpack.config.js file.
66
+
67
+ ```javascript
68
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
69
+ ```
70
+
71
+ Now, in the same config file, there should be a `module` object at the top of the config object, and somewhere under that, there should be a `rules` array. If either are missing, add them. Now, under `rules`, add this entry
72
+
73
+ ```javascript
74
+ {
75
+ test: /\.css$/,
76
+ use: [MiniCssExtractPlugin.loader, "css-loader"]
77
+ },
78
+ ```
79
+
80
+ Finally, under the plugins array, also at the top level of your webpack.config object (add it if necessary), add this
81
+
82
+ ```javascript
83
+ new MiniCssExtractPlugin({
84
+ filename: isProd ? "[name]-[contenthash].css" : "[name].css"
85
+ });
86
+ ```
87
+
88
+ If you're new to webpack, and that went a little too fast for you, check out the [webpack docs](https://webpack.js.org/plugins/mini-css-extract-plugin/#root) for a slower treatment of this.
89
+
90
+ Now, if we restart webpack, and reload our page, we should see this disgusting, but technically correct result
91
+
92
+ ![Unstyled Component](/css-modules/styledComponent.png)
93
+
94
+ "Success" - hooray.
95
+
96
+ ## Adding CSS Modules
97
+
98
+ Right now we have code-split css. We can load css within any JavaScript module which uses it, and the CSS will only load if, and when that JS module is loaded. However, the css is global; if we add style rules for `list-item` in any other .css file, they'll conflict with the styles in this one. Wouldn't it be nice if we could have these styles be scoped only to the JS module which loads them? We can, with css-modules.
99
+
100
+ css-modules are a pre-processor step on your css file. It runs through all of your class names, and makes them unique. Moreover, it creates an exported object from the css file, on which these unique class names are exposed.
101
+
102
+ To enable this behavior, we'll first tweak the webpack loader rule, like so
103
+
104
+ ```javascript
105
+ {
106
+ test: /\.css$/,
107
+ use: [
108
+ MiniCssExtractPlugin.loader,
109
+ {
110
+ loader: "css-loader",
111
+ options: { modules: true, exportOnlyLocals: false }
112
+ }
113
+ ]
114
+ };
115
+ ```
116
+
117
+ Note that the `exportOnlyLocals` may not be needed, as it should be the default; however, I've seen weird errors without it.
118
+
119
+ As we have it, our styles will still be loaded, but exposed behind dynamically generated class names. To apply them to our component at development time, we need to grab them off of the css module. Let's do that now
120
+
121
+ ```jsx
122
+ import styles from "./styles.css";
123
+ const { pane, list, ["list-item"]: listItem } = styles;
124
+
125
+ const Component = () => (
126
+ <div className={pane}>
127
+ <span>Pane Content</span>
128
+ <ul className={list}>
129
+ <li className={listItem}>Item 1</li>
130
+ <li className={listItem}>Item 2</li>
131
+ <li className={listItem}>Item 3</li>
132
+ </ul>
133
+ </div>
134
+ );
135
+ ```
136
+
137
+ We now import an object from the css file. The keys of this object are the class names we wrote originally in the css file, and the property values are the dynamically generated class names. Note the weird syntax around the `list-item` class. JavaScript identifiers cannot be hyphenated, so you'll either need to alias it, or just use valid JS names in your css modules.
138
+
139
+ _Edit_ - after publishing this, Marc Bernstein pointed out on Twitter that css-loader has a `camelCase` option that will convert hyphenated class names to camel-cased equivalents. You can read the docs on it [here](https://github.com/webpack-contrib/css-loader#camelcase)
140
+
141
+ Applying everything like so should reveal the same ugly output as before
142
+
143
+ ![Unstyled Component](/css-modules/styledComponent.png)
144
+
145
+ ## Best of Both Worlds?
146
+
147
+ So far so good, but what if, like me, you think global styles aren't so bad, _sometimes_. What if you have some styles that you plan to be universal in your app, used almost everywhere, and manually importing them as dynamic values just isn't worth the effort? Examples might include a `.btn`, `.table`, or even a `.pane` class. What if the `.pane` class is intended to be used far and wide, with exactly one meaning. Can we make that class (and others) be global, while using css-modules for module-specific stylings, like our list classes, above.
148
+
149
+ You can, and you have two options: you can define each and every global css class with `:global()` (see the [css-modules docs](https://github.com/css-modules/css-modules) for more info), or, my preferred approach, you can use a naming scheme to differentiate global css files from css-modules.
150
+
151
+ Specifically, what if we decide that files ending with `.module.css` are css modules, and any other `.css` file is an old-school, global css file. webpack makes this possible with the `oneOf` construct. Basically, turn your entry in the `rules` section, from before, into this
152
+
153
+ ```javascript
154
+ {
155
+ test: /\.css$/,
156
+ oneOf: [
157
+ {
158
+ test: /\.module\.css$/,
159
+ use: [
160
+ MiniCssExtractPlugin.loader,
161
+ {
162
+ loader: "css-loader",
163
+ options: { modules: true, exportOnlyLocals: false }
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ use: [MiniCssExtractPlugin.loader, "css-loader"]
169
+ }
170
+ ]
171
+ };
172
+ ```
173
+
174
+ This tells webpack to match `.css` files against the first rule that's valid. If the `.css` file ends in `.module.css`, use css modules. Else, use global styles. Let's try this out.
175
+
176
+ Let's rename our original `styles.css` to be `styles.module.css`, and remove the `.pane` styles. It'll look like this now
177
+
178
+ ```css
179
+ .list {
180
+ margin-left: 20px;
181
+ }
182
+
183
+ .list-item {
184
+ list-style-type: lower-greek;
185
+ }
186
+ ```
187
+
188
+ Now, let's add a new `styles.css` file, and put our `pane` styles from before, into it
189
+
190
+ ```css
191
+ .pane {
192
+ background-color: green;
193
+ max-width: 300px;
194
+ }
195
+
196
+ .pane span {
197
+ color: purple;
198
+ }
199
+ ```
200
+
201
+ Now, we'll import the global css styles (probably in one place, at the root of our application) like we did originally
202
+
203
+ ```javascript
204
+ import "./styles.css";
205
+ ```
206
+
207
+ and we'll grab the dynamic class names for the things we left in the css module, as we did above
208
+
209
+ ```jsx
210
+ import styles from "./styles.module.css";
211
+ const { list, ["list-item"]: listItem } = styles;
212
+
213
+ const Component = () => (
214
+ <div className="pane">
215
+ <span>Pane Content</span>
216
+ <ul className={list}>
217
+ <li className={listItem}>Item 1</li>
218
+ <li className={listItem}>Item 2</li>
219
+ <li className={listItem}>Item 3</li>
220
+ </ul>
221
+ </div>
222
+ );
223
+ ```
224
+
225
+ If all went well, everything should look identical to before.
226
+
227
+ ## Getting Sassy
228
+
229
+ Lastly, let's say you want to add Sass. Being subject to normal developer constraints, you certainly can't convert each and every css file to be scss, so you want to support both, side-by-side. Fortunately this is the easiest part of the post. Since scss is a superset of css, we can just run all `.css` and `.scss` files through the `sass-loader` as a first step, and leave all the rest of the css processing the same, as before. Let's see how.
230
+
231
+ First, we'll install some new dependencies
232
+
233
+ ```
234
+ npm i node-sass sass-loader --save
235
+ ```
236
+
237
+ Now, we'll add a slight tweak to our webpack rules
238
+
239
+ ```javascript
240
+ {
241
+ test: /\.s?css$/,
242
+ oneOf: [
243
+ {
244
+ test: /\.module\.s?css$/,
245
+ use: [
246
+ MiniCssExtractPlugin.loader,
247
+ {
248
+ loader: "css-loader",
249
+ options: { modules: true, exportOnlyLocals: false }
250
+ },
251
+ "sass-loader"
252
+ ]
253
+ },
254
+ {
255
+ use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
256
+ }
257
+ ]
258
+ };
259
+ ```
260
+
261
+ We added `sass-loader` as a new, first loader (loaders are processed from right to left). Did you catch the other change? It's the two `?`'s in the `test` properties. `?` means optional in regular expressions, so all this means is, our rules now apply to both `.css` and `.scss` files. Plain `.css` files are processed by the sass-loader, but again, css is a subset of `scss`, so this is effectively a no-op.
262
+
263
+ To make sure things still work, let's convert our css files to scss, add some Sass, and maybe even tweak the styles to be even cooler, and make sure everything still works.
264
+
265
+ First, for `styles.css`, we'll rename it to `styles.scss`, and add a few upgrades.
266
+
267
+ ```scss
268
+ $paneColor: pink;
269
+ $paneSpanColor: purple;
270
+
271
+ .pane {
272
+ background-color: $paneColor;
273
+ max-width: 300px;
274
+ }
275
+
276
+ .pane span {
277
+ color: $paneSpanColor;
278
+ }
279
+ ```
280
+
281
+ Now, we'll rename `styles.module.css` to be `styles.modules.scss` and make it look something like this
282
+
283
+ ```scss
284
+ $listStyleType: armenian;
285
+
286
+ .list {
287
+ margin-left: 20px;
288
+ }
289
+
290
+ .list-item {
291
+ list-style-type: $listStyleType;
292
+ }
293
+ ```
294
+
295
+ after re-starting our webpack process, our cool component should look like this
296
+
297
+ ![Unstyled Component](/css-modules/styledSass.png)
298
+
299
+ ## Concluding thoughts
300
+
301
+ In the end, a few lines of webpack config allowed us to easily load global, or scoped css, with optional sass processing in either case. Of course this is only scratching the surface of what's possible. There's no shortage of PostCSS, or other plugins you could toss into the loader list.
302
+
303
+ Happy Coding!
@@ -1,10 +1,4 @@
1
- <blurhash-image
2
- url="./img1.png"
3
- preview='{"blurhash":"U8SF;LD*%gofIUM|xuRj~qaeM{RjxtoIWBWC","w":364,"h":196}'
4
- >
5
- <img alt="A" src="./img1.png" slot="image" />
6
- <canvas width="364" height="196" slot="preview"></canvas>
7
- </blurhash-image>
1
+ ![A](./img1.png)
8
2
 
9
3
  <some-component>
10
4
  <p>Hello</p>
@@ -12,14 +6,5 @@
12
6
 
13
7
  Yo
14
8
 
15
- <blurhash-image
16
- url="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
17
- preview='{"blurhash":"U38|kkTJ01}A;{Or57;N01NG+?IW01rX^NAW","w":106,"h":160}'
18
- >
19
- <img
20
- alt="external image"
21
- src="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
22
- slot="image"
23
- />
24
- <canvas width="106" height="160" slot="preview"></canvas>
25
- </blurhash-image>
9
+ ![external image](https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg)
10
+
@@ -1,10 +1,4 @@
1
- <blurhash-image
2
- url="./img1.png"
3
- preview='{"blurhash":"U8SF;LD*%gofIUM|xuRj~qaeM{RjxtoIWBWC","w":364,"h":196}'
4
- >
5
- <img alt="A" src="./img1.png" slot="image" />
6
- <canvas width="364" height="196" slot="preview"></canvas>
7
- </blurhash-image>
1
+ ![A](./img1.png)
8
2
 
9
3
  <some-component>
10
4
  <p>Hello</p>
@@ -12,14 +6,5 @@
12
6
 
13
7
  Yo
14
8
 
15
- <blurhash-image
16
- url="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
17
- preview='{"blurhash":"U38|kkTJ01}A;{Or57;N01NG+?IW01rX^NAW","w":106,"h":160}'
18
- >
19
- <img
20
- alt="external image"
21
- src="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
22
- slot="image"
23
- />
24
- <canvas width="106" height="160" slot="preview"></canvas>
25
- </blurhash-image>
9
+ ![external image](https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg)
10
+
@@ -1,10 +1,4 @@
1
- <blurhash-image
2
- url="./img1.png"
3
- preview='{"blurhash":"U8SF;LD*%gofIUM|xuRj~qaeM{RjxtoIWBWC","w":364,"h":196}'
4
- >
5
- <img alt="A" src="./img1.png" slot="image" />
6
- <canvas width="364" height="196" slot="preview"></canvas>
7
- </blurhash-image>
1
+ ![A](./img1.png)
8
2
 
9
3
  <some-component>
10
4
  <p>Hello</p>
@@ -12,14 +6,5 @@
12
6
 
13
7
  Yo
14
8
 
15
- <blurhash-image
16
- url="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
17
- preview='{"blurhash":"U38|kkTJ01}A;{Or57;N01NG+?IW01rX^NAW","w":106,"h":160}'
18
- >
19
- <img
20
- alt="external image"
21
- src="https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg"
22
- slot="image"
23
- />
24
- <canvas width="106" height="160" slot="preview"></canvas>
25
- </blurhash-image>
9
+ ![external image](https://d193qjyckdxivp.cloudfront.net/medium-covers/573d1b97120426ef0078aa92/fcb820e4-36e3-4741-a3de-6994c46a66cc.jpg)
10
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-blurhash-previews",
3
- "version": "0.0.3-beta4",
3
+ "version": "0.0.3-beta5",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -30,10 +30,13 @@
30
30
  "blurhash": "^1.1.5",
31
31
  "colors": "^1.4.0",
32
32
  "glob": "^8.0.3",
33
+ "install": "^0.13.0",
33
34
  "next": "^12.2.0",
34
35
  "node-fetch": "^3.2.6",
36
+ "npm": "^8.15.1",
35
37
  "prettier": "^2.7.1",
36
38
  "remark": "^14.0.2",
39
+ "remark-frontmatter": "^4.0.1",
37
40
  "retext": "^8.1.0",
38
41
  "sharp": "^0.30.7",
39
42
  "to-vfile": "^7.2.3",