Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 98 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ Install this grunt plugin next to your project's [Gruntfile.js](http://gruntjs.c

```bash
yarn add webpack grunt-webpack --dev
```

You can still use npm

```bash
npm i webpack grunt-webpack --save-dev
// or
// npm i webpack grunt-webpack --save-dev
```

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

```javascript
const webpackConfig = require('./webpack.config.js');

module.exports = function(grunt) {

// Project configuration.
grunt.initConfig({
grunt.initConfig({
...,
webpack: {
myConfig: {
// your webpack config
},
myConfig: webpackConfig,
},
...
});
Expand Down Expand Up @@ -121,11 +117,13 @@ The webpack-dev-server options [`host`][5], [`hotOnly`][6], [`inline`][1], [`por

### Webpack

#### imported config

This is a simple example that requires the webpack config from the config file.
It also disables stats in non 'development' environments and enables watch in development.

``` javascript
const webpackConfig = require('./webpack.config');
const webpackConfig = require('./webpack.config.js');

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

> For more examples and information have a look at the [webpack documentation][9] which mostly also applies here besides the noted differences above.

#### Lazy config loading

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).

```js
const webpackConfig = require('./webpack.config.js');

module.exports = function(grunt) {
grunt.initConfig({
webpack: {
myconfig: () => ({
entry: path.join(__dirname, "entry"),
output: {
path: __dirname,
filename: "output.js",
},
}),
},
});

grunt.loadNpmTasks('grunt-webpack');
};
```

#### Grunt templates

grunt-webpack supports grunt templates in all string values in it's configuration.

In the next example we use a template for `output.filename`.

```js
const webpackConfig = require('./webpack.config.js');

module.exports = function(grunt) {
grunt.initConfig({
outputFileName: "output.js",
webpack: {
myconfig: {
entry: path.join(__dirname, "entry"),
output: {
path: __dirname,
filename: "<%= outputFileName %>",
},
},
},
});

grunt.loadNpmTasks('grunt-webpack');
};
```

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:

```js
const webpackConfig = require('./webpack.config.js');

module.exports = function(grunt) {
grunt.initConfig({
name: "Webpack",
pkg: {
copyright: '<%= name %>',
version: '6.55.345',
},
webpack: {
myconfig: (config) => ({
entry: path.join(__dirname, "entry"),
output: {
path: __dirname,
filename: "output.js",
},
plugins: [
new webpack.BannerPlugin({
banner: `/*! ${config.pkg.copyright} - Version ${config.pkg.version} dated ${grunt.template.today()} */`,
raw: true,
}),
],
}),
},
});

grunt.loadNpmTasks('grunt-webpack');
};
```

<h2 align="center">Troubleshooting</h2>

### Circular reference detected (.plugins)

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

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

```js
const webpackConfig = require('./webpack.config.js');

module.exports = function(grunt) {
grunt.initConfig({
webpack: {
myconfig: function() {
return {
plugins: [...]
};
}
}
myconfig: () => webpackConfig,
},
});

grunt.loadNpmTasks('grunt-webpack');
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"ava": "^0.25.0",
"ava": "^1.2.1",
"babel-loader": "^8.0.1",
"conventional-github-releaser": "^3.1.2",
"eslint": "^5.5.0",
Expand All @@ -52,7 +52,7 @@
},
"dependencies": {
"deep-for-each": "^2.0.2",
"lodash": "^4.7.15"
"lodash": "^4.17.11"
},
"ava": {
"files": [
Expand Down
48 changes: 6 additions & 42 deletions src/options/OptionHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@
const deepForEach = require('deep-for-each');
const defaults = require('./default');

const PLUGIN_PROPS = [
'plugins',
'resolve.plugins',
'webpack.plugins',
'webpack.resolve.plugins'
];

class OptionHelper {

constructor(grunt, taskName, target) {
Expand All @@ -18,13 +11,13 @@ class OptionHelper {
}

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

return defaults.mergeOptions(
this.getDefaultOptions(),
baseOptions,
this.getWithPlugins([this.taskName, this.target])
this.getRawConfig([this.taskName, this.target])
);
}

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

getWithPlugins(ns) {
getRawConfig(ns) {
let obj = this.grunt.config.getRaw(ns) || {};

if (typeof obj === 'function') {
obj = obj();
obj = obj(this.grunt.config.get());
}

deepForEach(obj, function (value, key, parent, path) {
deepForEach(obj, (value, key, parent) => {
if (typeof value === 'string') {
parent[key] = this.grunt.config.process(value);
} else if (PLUGIN_PROPS.indexOf(path) !== -1 && Array.isArray(value)) {
parent[key] = value.map(plugin => this.fixPlugin(plugin));
}
}.bind(this));

return obj;
}

fixPlugin(plugin) {
if (typeof plugin === 'function') return plugin;

// Operate on a copy of the plugin, since the webpack task
// can be called multiple times for one instance of a plugin
const instance = Object.create(plugin);
const grunt = this.grunt;
Object.keys(plugin).forEach((key) => {
if (typeof plugin[key] === 'string') {
instance[key] = grunt.config.process(plugin[key]);
} else if (typeof plugin[key] === 'function') {
instance[key] = function () {
let value = plugin[key].apply(instance, arguments);
if (typeof value === 'string') {
value = grunt.config.process(value);
}

return value;
};
} else {
instance[key] = plugin[key];
}
});

return instance;
return obj;
}

filterGruntOptions(options) {
Expand Down
13 changes: 7 additions & 6 deletions tasks/webpack-dev-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ npm install --save-dev webpack-dev-server
grunt.registerTask('webpack-dev-server', 'Start a webpack-dev-server.', function webpackDevServerTask(cliTarget) {
const done = this.async();

const config = grunt.config([this.name]);
const targets = cliTarget
? [cliTarget]
: config
? Object.keys(config)
: [];
let targets;
if (cliTarget) {
targets = [cliTarget];
} else {
const config = grunt.config.getRaw([this.name]);
targets = config ? Object.keys(config) : [];
}

let runningTargetCount = targets.length;
let keepalive = false;
Expand Down
13 changes: 7 additions & 6 deletions tasks/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ module.exports = (grunt) => {
grunt.registerTask('webpack', 'Run webpack.', function webpackTask(cliTarget) {
const done = this.async();

const config = grunt.config([this.name]);
const targets = cliTarget
? [cliTarget]
: config
? Object.keys(config)
: [];
let targets;
if (cliTarget) {
targets = [cliTarget];
} else {
const config = grunt.config.getRaw([this.name]);
targets = config ? Object.keys(config) : [];
}
let runningTargetCount = targets.length;
let keepalive = false;

Expand Down
12 changes: 7 additions & 5 deletions tests/fixtures/webpack/banner-plugin-webpack-4/Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@ const loadGruntWebpackTasks = require('../../../utils/loadGruntWebpackTasks');

module.exports = function (grunt) {
grunt.initConfig({
name: "Webpack",
outputFileName: "output.js",
pkg: {
copyright: 'Webpack',
copyright: '<%= name %>',
version: '6.55.345',
},
webpack: {
test: {
test: (config) =>({
entry: path.join(__dirname, "entry"),
output: {
path: __dirname,
filename: "output.js",
filename: "<%= outputFileName %>",
},
plugins: [
new webpack.BannerPlugin({
banner: '/*! <%= pkg.copyright %> - Version <%= pkg.version %> dated <%= grunt.template.today() %> */',
banner: `/*! ${config.pkg.copyright} - Version ${config.pkg.version} dated ${grunt.template.today()} */`,
raw: true,
}),
],
},
}),
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ plugin.circle = plugin;
module.exports = function (grunt) {
grunt.initConfig({
webpack: {
test: function() {
return {
test: {
entry: path.join(__dirname, "entry"),
output: {
path: __dirname,
Expand All @@ -18,8 +17,7 @@ module.exports = function (grunt) {
plugins: [
plugin,
]
};
},
}
},
});

Expand Down
Loading