Skip to content

Commit e31fccb

Browse files
authored
Merge pull request #171 from webpack-contrib/better-integration
Better integration with grunt
2 parents 11b9b9a + 3e1a436 commit e31fccb

File tree

10 files changed

+2389
-2094
lines changed

10 files changed

+2389
-2094
lines changed

README.md

Lines changed: 98 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,8 @@ Install this grunt plugin next to your project's [Gruntfile.js](http://gruntjs.c
2222

2323
```bash
2424
yarn add webpack grunt-webpack --dev
25-
```
26-
27-
You can still use npm
28-
29-
```bash
30-
npm i webpack grunt-webpack --save-dev
25+
// or
26+
// npm i webpack grunt-webpack --save-dev
3127
```
3228

3329
If you also want to use the webpack-dev-server task you also need to install `webpack-dev-server`
@@ -39,15 +35,15 @@ yarn add webpack-dev-server --dev
3935
Then add this line to your project's `Gruntfile.js` gruntfile:
4036

4137
```javascript
38+
const webpackConfig = require('./webpack.config.js');
39+
4240
module.exports = function(grunt) {
4341

4442
// Project configuration.
45-
grunt.initConfig({
43+
grunt.initConfig({
4644
...,
4745
webpack: {
48-
myConfig: {
49-
// your webpack config
50-
},
46+
myConfig: webpackConfig,
5147
},
5248
...
5349
});
@@ -121,11 +117,13 @@ The webpack-dev-server options [`host`][5], [`hotOnly`][6], [`inline`][1], [`por
121117

122118
### Webpack
123119

120+
#### imported config
121+
124122
This is a simple example that requires the webpack config from the config file.
125123
It also disables stats in non 'development' environments and enables watch in development.
126124

127125
``` javascript
128-
const webpackConfig = require('./webpack.config');
126+
const webpackConfig = require('./webpack.config.js');
129127

130128
module.exports = function(grunt) {
131129
grunt.initConfig({
@@ -159,25 +157,107 @@ On the command line you can then do the following.
159157

160158
> For more examples and information have a look at the [webpack documentation][9] which mostly also applies here besides the noted differences above.
161159
160+
#### Lazy config loading
161+
162+
In some cases you might want to load the webpack config lazy. This can be done by specifying a function as the config value. The first paramter to this function will be the complete grunt config, which can be used in cases where grunt templates do not work (see below).
163+
164+
```js
165+
const webpackConfig = require('./webpack.config.js');
166+
167+
module.exports = function(grunt) {
168+
grunt.initConfig({
169+
webpack: {
170+
myconfig: () => ({
171+
entry: path.join(__dirname, "entry"),
172+
output: {
173+
path: __dirname,
174+
filename: "output.js",
175+
},
176+
}),
177+
},
178+
});
179+
180+
grunt.loadNpmTasks('grunt-webpack');
181+
};
182+
```
183+
184+
#### Grunt templates
185+
186+
grunt-webpack supports grunt templates in all string values in it's configuration.
187+
188+
In the next example we use a template for `output.filename`.
189+
190+
```js
191+
const webpackConfig = require('./webpack.config.js');
192+
193+
module.exports = function(grunt) {
194+
grunt.initConfig({
195+
outputFileName: "output.js",
196+
webpack: {
197+
myconfig: {
198+
entry: path.join(__dirname, "entry"),
199+
output: {
200+
path: __dirname,
201+
filename: "<%= outputFileName %>",
202+
},
203+
},
204+
},
205+
});
206+
207+
grunt.loadNpmTasks('grunt-webpack');
208+
};
209+
```
210+
211+
For plugins we cannot support grunt template interpolation, as plugins are class instances which we cannot modify during runtime without breaking them. If you need to use template in a string option to a plugin, you can use lazy config loading and use the supplied config. You can also use grunt inside directly to access utility methods:
212+
213+
```js
214+
const webpackConfig = require('./webpack.config.js');
215+
216+
module.exports = function(grunt) {
217+
grunt.initConfig({
218+
name: "Webpack",
219+
pkg: {
220+
copyright: '<%= name %>',
221+
version: '6.55.345',
222+
},
223+
webpack: {
224+
myconfig: (config) => ({
225+
entry: path.join(__dirname, "entry"),
226+
output: {
227+
path: __dirname,
228+
filename: "output.js",
229+
},
230+
plugins: [
231+
new webpack.BannerPlugin({
232+
banner: `/*! ${config.pkg.copyright} - Version ${config.pkg.version} dated ${grunt.template.today()} */`,
233+
raw: true,
234+
}),
235+
],
236+
}),
237+
},
238+
});
239+
240+
grunt.loadNpmTasks('grunt-webpack');
241+
};
242+
```
243+
162244
<h2 align="center">Troubleshooting</h2>
163245

164246
### Circular reference detected (.plugins)
165247

166248
If you encounter this message it means that one of the plugins which are present in your config have circular references.
167-
This is totally fine for webpack, but sadly grunt cannot handle these.
249+
This is not a bug in the plugin and is totally fine for webpack, but sadly grunt cannot handle these.
168250

169251
To workaround this problem use lazy config loading, by wrapping your config inside a function.
170252

171253
```js
254+
const webpackConfig = require('./webpack.config.js');
255+
172256
module.exports = function(grunt) {
173257
grunt.initConfig({
174258
webpack: {
175-
myconfig: function() {
176-
return {
177-
plugins: [...]
178-
};
179-
}
180-
}
259+
myconfig: () => webpackConfig,
260+
},
181261
});
182262

183263
grunt.loadNpmTasks('grunt-webpack');

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"devDependencies": {
4040
"@babel/core": "^7.0.0",
4141
"@babel/preset-env": "^7.0.0",
42-
"ava": "^0.25.0",
42+
"ava": "^1.2.1",
4343
"babel-loader": "^8.0.1",
4444
"conventional-github-releaser": "^3.1.2",
4545
"eslint": "^5.5.0",
@@ -52,7 +52,7 @@
5252
},
5353
"dependencies": {
5454
"deep-for-each": "^2.0.2",
55-
"lodash": "^4.7.15"
55+
"lodash": "^4.17.11"
5656
},
5757
"ava": {
5858
"files": [

src/options/OptionHelper.js

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22
const deepForEach = require('deep-for-each');
33
const defaults = require('./default');
44

5-
const PLUGIN_PROPS = [
6-
'plugins',
7-
'resolve.plugins',
8-
'webpack.plugins',
9-
'webpack.resolve.plugins'
10-
];
11-
125
class OptionHelper {
136

147
constructor(grunt, taskName, target) {
@@ -18,13 +11,13 @@ class OptionHelper {
1811
}
1912

2013
generateOptions() {
21-
const baseOptions = this.getWithPlugins([this.taskName, 'options']);
14+
const baseOptions = this.getRawConfig([this.taskName, 'options']);
2215
if (Array.isArray(baseOptions)) throw new Error('webpack.options must be an object, but array was provided');
2316

2417
return defaults.mergeOptions(
2518
this.getDefaultOptions(),
2619
baseOptions,
27-
this.getWithPlugins([this.taskName, this.target])
20+
this.getRawConfig([this.taskName, this.target])
2821
);
2922
}
3023

@@ -55,49 +48,20 @@ class OptionHelper {
5548
return typeof option === 'function' ? option(options) : option;
5649
}
5750

58-
getWithPlugins(ns) {
51+
getRawConfig(ns) {
5952
let obj = this.grunt.config.getRaw(ns) || {};
6053

6154
if (typeof obj === 'function') {
62-
obj = obj();
55+
obj = obj(this.grunt.config.get());
6356
}
6457

65-
deepForEach(obj, function (value, key, parent, path) {
58+
deepForEach(obj, (value, key, parent) => {
6659
if (typeof value === 'string') {
6760
parent[key] = this.grunt.config.process(value);
68-
} else if (PLUGIN_PROPS.indexOf(path) !== -1 && Array.isArray(value)) {
69-
parent[key] = value.map(plugin => this.fixPlugin(plugin));
70-
}
71-
}.bind(this));
72-
73-
return obj;
74-
}
75-
76-
fixPlugin(plugin) {
77-
if (typeof plugin === 'function') return plugin;
78-
79-
// Operate on a copy of the plugin, since the webpack task
80-
// can be called multiple times for one instance of a plugin
81-
const instance = Object.create(plugin);
82-
const grunt = this.grunt;
83-
Object.keys(plugin).forEach((key) => {
84-
if (typeof plugin[key] === 'string') {
85-
instance[key] = grunt.config.process(plugin[key]);
86-
} else if (typeof plugin[key] === 'function') {
87-
instance[key] = function () {
88-
let value = plugin[key].apply(instance, arguments);
89-
if (typeof value === 'string') {
90-
value = grunt.config.process(value);
91-
}
92-
93-
return value;
94-
};
95-
} else {
96-
instance[key] = plugin[key];
9761
}
9862
});
9963

100-
return instance;
64+
return obj;
10165
}
10266

10367
filterGruntOptions(options) {

tasks/webpack-dev-server.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ npm install --save-dev webpack-dev-server
5757
grunt.registerTask('webpack-dev-server', 'Start a webpack-dev-server.', function webpackDevServerTask(cliTarget) {
5858
const done = this.async();
5959

60-
const config = grunt.config([this.name]);
61-
const targets = cliTarget
62-
? [cliTarget]
63-
: config
64-
? Object.keys(config)
65-
: [];
60+
let targets;
61+
if (cliTarget) {
62+
targets = [cliTarget];
63+
} else {
64+
const config = grunt.config.getRaw([this.name]);
65+
targets = config ? Object.keys(config) : [];
66+
}
6667

6768
let runningTargetCount = targets.length;
6869
let keepalive = false;

tasks/webpack.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ module.exports = (grunt) => {
1212
grunt.registerTask('webpack', 'Run webpack.', function webpackTask(cliTarget) {
1313
const done = this.async();
1414

15-
const config = grunt.config([this.name]);
16-
const targets = cliTarget
17-
? [cliTarget]
18-
: config
19-
? Object.keys(config)
20-
: [];
15+
let targets;
16+
if (cliTarget) {
17+
targets = [cliTarget];
18+
} else {
19+
const config = grunt.config.getRaw([this.name]);
20+
targets = config ? Object.keys(config) : [];
21+
}
2122
let runningTargetCount = targets.length;
2223
let keepalive = false;
2324

tests/fixtures/webpack/banner-plugin-webpack-4/Gruntfile.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@ const loadGruntWebpackTasks = require('../../../utils/loadGruntWebpackTasks');
44

55
module.exports = function (grunt) {
66
grunt.initConfig({
7+
name: "Webpack",
8+
outputFileName: "output.js",
79
pkg: {
8-
copyright: 'Webpack',
10+
copyright: '<%= name %>',
911
version: '6.55.345',
1012
},
1113
webpack: {
12-
test: {
14+
test: (config) =>({
1315
entry: path.join(__dirname, "entry"),
1416
output: {
1517
path: __dirname,
16-
filename: "output.js",
18+
filename: "<%= outputFileName %>",
1719
},
1820
plugins: [
1921
new webpack.BannerPlugin({
20-
banner: '/*! <%= pkg.copyright %> - Version <%= pkg.version %> dated <%= grunt.template.today() %> */',
22+
banner: `/*! ${config.pkg.copyright} - Version ${config.pkg.version} dated ${grunt.template.today()} */`,
2123
raw: true,
2224
}),
2325
],
24-
},
26+
}),
2527
},
2628
});
2729

tests/fixtures/webpack/circular-reference-in-options/Gruntfile.js renamed to tests/fixtures/webpack/circular-reference-in-plugin-options/Gruntfile.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ plugin.circle = plugin;
88
module.exports = function (grunt) {
99
grunt.initConfig({
1010
webpack: {
11-
test: function() {
12-
return {
11+
test: {
1312
entry: path.join(__dirname, "entry"),
1413
output: {
1514
path: __dirname,
@@ -18,8 +17,7 @@ module.exports = function (grunt) {
1817
plugins: [
1918
plugin,
2019
]
21-
};
22-
},
20+
}
2321
},
2422
});
2523

0 commit comments

Comments
 (0)