Skip to content

Commit d9a178c

Browse files
barskernKyleAMathews
authored andcommitted
[gatsby-plugin-less] Extend less-plugin with support for modifyVars (#3801)
* [gatsby-plugin-less] Extend less-plugin with support for `modifyVars` The less plugin did its job, but when I was going to use it with a library I experienced that it was lacking the ability to modify less-variables. This made it hard to customize less libraries. By letting the user provide a `options` in `gatsby-config.js`, the plugin can overwrite variables defined in the less stylesheet and hence makes it a breeze to customize libraries. The user has two options to include vars: either a object defined directly in the `gatsby-config.js` or define a file which exports an object that will be used as the options. * Update README.md
1 parent e5993ce commit d9a178c

File tree

5 files changed

+225
-18
lines changed

5 files changed

+225
-18
lines changed
Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
11
# gatsby-plugin-less
22

3-
Stub README
3+
Adds the ability to load and parse Less-flavored CSS.
4+
5+
## Install
6+
7+
`npm install --save gatsby-plugin-less`
8+
9+
## How to use
10+
11+
Add the plugin to your `gatsby-config.js`.
12+
13+
```javascript
14+
plugins: [`gatsby-plugin-plugin-less`];
15+
```
16+
17+
By default this plugin will compile `*.less` and `*.module.less` files. The plugin can also be used with `modifyVars` as it is explained [here](http://lesscss.org/usage/). By defining a javascript object you can overwrite less-variables. This can be useful when using a component library like [antd](https://ant.design/docs/react/introduce).
18+
19+
```javascript
20+
plugins: [
21+
{
22+
resolve: `gatsby-plugin-less`,
23+
options: {
24+
theme: {
25+
'text-color': `#fff`
26+
},
27+
},
28+
},
29+
];
30+
```
31+
32+
Or you can specify a file which exports a object in the same form.
33+
34+
```javascript
35+
plugins: [
36+
{
37+
resolve: `gatsby-plugin-less`,
38+
options: {
39+
theme: `./src/theme.js`
40+
},
41+
},
42+
];
43+
```
44+
45+
In file `./src/theme.js`:
46+
```javascript
47+
module.exports = {
48+
'text-color': `#fff`
49+
}
50+
```

packages/gatsby-plugin-less/package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
{
22
"name": "gatsby-plugin-less",
3-
"description": "Stub description for gatsby-plugin-less",
4-
"version": "1.0.9",
3+
"description": "Adds the ability to load and parse less-files to include in project your",
4+
"version": "1.1.0",
55
"author": "Ming Aldrich-Gan <[email protected]>",
6+
"contributors": [
7+
"Ole Martin Ruud <[email protected]> (barskern.github.io)"
8+
],
69
"dependencies": {
710
"babel-runtime": "^6.26.0",
811
"extract-text-webpack-plugin": "^1.0.1",
@@ -25,8 +28,8 @@
2528
"license": "MIT",
2629
"main": "index.js",
2730
"scripts": {
28-
"build": "babel src --out-dir . --ignore __tests__",
31+
"build": "babel src --out-dir . --ignore __tests__,theme-test.js",
2932
"prepublish": "cross-env NODE_ENV=production npm run build",
30-
"watch": "babel -w src --out-dir . --ignore __tests__"
33+
"watch": "babel -w src --out-dir . --ignore __tests__,theme-test.js"
3134
}
3235
}

packages/gatsby-plugin-less/src/__tests__/gatsby-node.js

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,27 @@ describe(`gatsby-plugin-less`, () => {
66
},
77
}
88
})
9+
const filePathTheme = `./packages/gatsby-plugin-less/src/theme-test.js`
910

1011
const { modifyWebpackConfig } = require(`../gatsby-node`)
1112
const cssLoader = expect.stringMatching(/^css/)
13+
14+
const lessLoaderDevNoVars = `less?{"sourceMap":true}`
15+
const lessLoaderProdNoVars = `less`
16+
17+
const lessLoaderDevVars = `less?{"sourceMap":true,"modifyVars":{"text-color":"#fff"}}`
18+
const lessLoaderProdVars = `less?{"modifyVars":{"text-color":"#fff"}}`
1219
;[
1320
{
1421
stages: [`develop`],
1522
loaderKeys: [`less`, `lessModules`],
1623
loaderConfig: {
17-
loaders: expect.arrayContaining([cssLoader, `less`]),
24+
loaders: expect.arrayContaining([cssLoader, lessLoaderDevVars]),
25+
},
26+
options: {
27+
theme: {
28+
'text-color': `#fff`,
29+
},
1830
},
1931
},
2032
{
@@ -23,27 +35,140 @@ describe(`gatsby-plugin-less`, () => {
2335
loaderConfig: {
2436
loader: {
2537
extractTextCalledWithArgs: expect.arrayContaining([
26-
expect.arrayContaining([cssLoader, `less`]),
38+
expect.arrayContaining([cssLoader, lessLoaderProdVars]),
39+
]),
40+
},
41+
},
42+
options: {
43+
theme: {
44+
'text-color': `#fff`,
45+
},
46+
},
47+
},
48+
{
49+
stages: [`develop-html`, `build-html`, `build-javascript`],
50+
loaderKeys: [`lessModules`],
51+
loaderConfig: {
52+
loader: {
53+
extractTextCalledWithArgs: expect.arrayContaining([
54+
expect.arrayContaining([cssLoader, lessLoaderProdVars]),
2755
]),
2856
},
2957
},
58+
options: {
59+
theme: {
60+
'text-color': `#fff`,
61+
},
62+
},
63+
},
64+
].forEach(({ stages, loaderKeys, loaderConfig, options }) => {
65+
stages.forEach(stage => {
66+
it(`modifies webpack config with theme object for stage: ${stage}`, () => {
67+
const config = { loader: jest.fn() }
68+
const modified = modifyWebpackConfig({ config, stage }, options)
69+
70+
expect(modified).toBe(config)
71+
72+
loaderKeys.forEach(loaderKey =>
73+
expect(config.loader).toBeCalledWith(
74+
loaderKey,
75+
expect.objectContaining(loaderConfig)
76+
)
77+
)
78+
})
79+
})
80+
})
81+
;[
82+
{
83+
stages: [`develop`],
84+
loaderKeys: [`less`, `lessModules`],
85+
loaderConfig: {
86+
loaders: expect.arrayContaining([cssLoader, lessLoaderDevVars]),
87+
},
88+
options: {
89+
theme: filePathTheme,
90+
},
91+
},
92+
{
93+
stages: [`build-css`],
94+
loaderKeys: [`less`, `lessModules`],
95+
loaderConfig: {
96+
loader: {
97+
extractTextCalledWithArgs: expect.arrayContaining([
98+
expect.arrayContaining([cssLoader, lessLoaderProdVars]),
99+
]),
100+
},
101+
},
102+
options: {
103+
theme: filePathTheme,
104+
},
105+
},
106+
{
107+
stages: [`develop-html`, `build-html`, `build-javascript`],
108+
loaderKeys: [`lessModules`],
109+
loaderConfig: {
110+
loader: {
111+
extractTextCalledWithArgs: expect.arrayContaining([
112+
expect.arrayContaining([cssLoader, lessLoaderProdVars]),
113+
]),
114+
},
115+
},
116+
options: {
117+
theme: filePathTheme,
118+
},
119+
},
120+
].forEach(({ stages, loaderKeys, loaderConfig, options }) => {
121+
stages.forEach(stage => {
122+
it(`modifies webpack config with theme path for stage: ${stage}`, () => {
123+
const config = { loader: jest.fn() }
124+
const modified = modifyWebpackConfig({ config, stage }, options)
125+
126+
expect(modified).toBe(config)
127+
128+
loaderKeys.forEach(loaderKey =>
129+
expect(config.loader).toBeCalledWith(
130+
loaderKey,
131+
expect.objectContaining(loaderConfig)
132+
)
133+
)
134+
})
135+
})
136+
})
137+
;[
138+
{
139+
stages: [`develop`],
140+
loaderKeys: [`less`, `lessModules`],
141+
loaderConfig: {
142+
loaders: expect.arrayContaining([cssLoader, lessLoaderDevNoVars]),
143+
},
144+
},
145+
{
146+
stages: [`build-css`],
147+
loaderKeys: [`less`, `lessModules`],
148+
loaderConfig: {
149+
loader: {
150+
extractTextCalledWithArgs: expect.arrayContaining([
151+
expect.arrayContaining([cssLoader, lessLoaderProdNoVars]),
152+
]),
153+
},
154+
},
30155
},
31156
{
32157
stages: [`develop-html`, `build-html`, `build-javascript`],
33158
loaderKeys: [`lessModules`],
34159
loaderConfig: {
35160
loader: {
36161
extractTextCalledWithArgs: expect.arrayContaining([
37-
expect.arrayContaining([cssLoader, `less`]),
162+
expect.arrayContaining([cssLoader, lessLoaderProdNoVars]),
38163
]),
39164
},
40165
},
41166
},
42167
].forEach(({ stages, loaderKeys, loaderConfig }) => {
43168
stages.forEach(stage => {
44-
it(`modifies webpack config for stage: ${stage}`, () => {
169+
it(`modifies webpack config without options for stage: ${stage}`, () => {
45170
const config = { loader: jest.fn() }
46-
const modified = modifyWebpackConfig({ config, stage })
171+
const modified = modifyWebpackConfig({ config, stage }, {})
47172

48173
expect(modified).toBe(config)
49174

packages/gatsby-plugin-less/src/gatsby-node.js

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,65 @@
1-
import ExtractTextPlugin from "extract-text-webpack-plugin"
2-
import { cssModulesConfig } from "gatsby-1-config-css-modules"
1+
import ExtractTextPlugin from 'extract-text-webpack-plugin'
2+
import { cssModulesConfig } from 'gatsby-1-config-css-modules'
3+
import path from 'path'
34

4-
exports.modifyWebpackConfig = ({ config, stage }) => {
5+
exports.modifyWebpackConfig = ({ config, stage }, { theme }) => {
56
const lessFiles = /\.less$/
67
const lessModulesFiles = /\.module\.less$/
78

9+
let themeJson = ``
10+
11+
if (typeof theme === `string` && theme !== ``) {
12+
try {
13+
const themeFile = require(path.resolve(theme))
14+
themeJson = JSON.stringify(themeFile)
15+
} catch (err) {
16+
throw new Error(`Couldn't convert js to json object at path: '${theme}'\n${err}`)
17+
}
18+
} else if (typeof theme === `object`) {
19+
try {
20+
themeJson = JSON.stringify(theme)
21+
} catch (err) {
22+
throw new Error(`Couldn't convert javascript object to json object.\n${err}`)
23+
}
24+
}
25+
26+
let lessLoaderDev = ``
27+
let lessLoaderProd = ``
28+
29+
if (themeJson) {
30+
lessLoaderDev = `less?{"sourceMap":true,"modifyVars":${themeJson}}`
31+
lessLoaderProd = `less?{"modifyVars":${themeJson}}`
32+
} else {
33+
lessLoaderDev = `less?{"sourceMap":true}`
34+
lessLoaderProd = `less`
35+
}
36+
837
switch (stage) {
938
case `develop`: {
1039
config.loader(`less`, {
1140
test: lessFiles,
1241
exclude: lessModulesFiles,
13-
loaders: [`style`, `css`, `less`],
42+
loaders: [`style`, `css`, lessLoaderDev],
1443
})
1544

1645
config.loader(`lessModules`, {
1746
test: lessModulesFiles,
18-
loaders: [`style`, cssModulesConfig(stage), `less`],
47+
loaders: [`style`, cssModulesConfig(stage), lessLoaderDev],
1948
})
2049
return config
2150
}
2251
case `build-css`: {
2352
config.loader(`less`, {
2453
test: lessFiles,
2554
exclude: lessModulesFiles,
26-
loader: ExtractTextPlugin.extract([`css?minimize`, `less`]),
55+
loader: ExtractTextPlugin.extract([`css?minimize`, lessLoaderProd]),
2756
})
2857

2958
config.loader(`lessModules`, {
3059
test: lessModulesFiles,
3160
loader: ExtractTextPlugin.extract(`style`, [
3261
cssModulesConfig(stage),
33-
`less`,
62+
lessLoaderProd,
3463
]),
3564
})
3665
return config
@@ -48,7 +77,7 @@ exports.modifyWebpackConfig = ({ config, stage }) => {
4877
test: lessModulesFiles,
4978
loader: ExtractTextPlugin.extract(`style`, [
5079
cssModulesConfig(stage),
51-
`less`,
80+
lessLoaderProd,
5281
]),
5382
})
5483
return config
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
'text-color': `#fff`,
3+
}

0 commit comments

Comments
 (0)