Skip to content

Commit

Permalink
Rfc/issue 183 webpack plugin type (#191)
Browse files Browse the repository at this point in the history
* unit tests for supporting a webpack plugin in the Greenwood build

* documentation

* fix spec description

* clear up docs example

* clear up docs example
  • Loading branch information
thescientist13 authored Sep 11, 2019
1 parent 770e940 commit 019a751
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 7 deletions.
10 changes: 9 additions & 1 deletion packages/cli/src/config/webpack.config.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = ({ config, context }) => {
}
];

// gets Index Hooks to pass as options to HtmlWebpackPlugin
const customOptions = Object.assign({}, ...config.plugins
.filter((plugin) => plugin.type === 'index')
.map((plugin) => plugin.provider())
Expand All @@ -62,6 +63,11 @@ module.exports = ({ config, context }) => {
});
}));

// gets webpack plugins passed in directly by fhe user
const customWebpackPlugins = config.plugins
.filter((plugin) => plugin.type === 'webpack')
.map((plugin) => plugin.provider());

return {
entry: {
index: path.join(context.scratchDir, 'app', 'app.js')
Expand Down Expand Up @@ -131,7 +137,9 @@ module.exports = ({ config, context }) => {
template: path.join(context.scratchDir, context.indexPageTemplate),
chunksSortMode: 'dependency',
...customOptions
})
}),

...customWebpackPlugins
]
};
};
4 changes: 2 additions & 2 deletions packages/cli/src/lifecycles/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ module.exports = readAndMergeConfig = async() => {
}

if (plugins && plugins.length > 0) {
const types = ['index'];
const types = ['index', 'webpack'];

plugins.forEach(plugin => {
if (!plugin.type || types.indexOf(plugin.type) < 0) {
reject(`Error: greenwood.config.js plugins must be one of type "${types.join(',')}". got "${plugin.type}" instead.`);
reject(`Error: greenwood.config.js plugins must be one of type "${types.join(', ')}". got "${plugin.type}" instead.`);
}

if (!plugin.provider || typeof plugin.provider !== 'function') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Build Greenwood With: ', () => {
try {
await setup.runGreenwoodCommand('build');
} catch (err) {
expect(err).to.contain('Error: greenwood.config.js plugins must be one of type "index". got "indexxx" instead.');
expect(err).to.contain('Error: greenwood.config.js plugins must be one of type "index, webpack". got "indexxx" instead.');
}
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Use Case
* Run Greenwood with some plugins and default workspace.
*
* Uaer Result
* Should generate a bare bones Greenwood build with certain plugins injected into index.html.
*
* User Command
* greenwood build
*
* User Config
* const webpack = require('webpack');
*
* {
* plugins: [{
* type: 'weboack',
* provider: () => {
* return new webpack.BannerPlugin('Some custom text')
* }
* }]
* }
*
* User Workspace
* Greenwood default (src/)
*/
const expect = require('chai').expect;
const fs = require('fs');
const { JSDOM } = require('jsdom');
const path = require('path');
const runSmokeTest = require('../../../../../test/smoke-test');
const TestBed = require('../../../../../test/test-bed');
const { version } = require('../../../package.json');

describe('Build Greenwood With: ', async function() {
const mockBanner = `My Banner - v${version}`;
const LABEL = 'Custom Webpack Plugin and Default Workspace';
let setup;

before(async function() {
setup = new TestBed();
this.context = setup.setupTestBed(__dirname);
});

describe(LABEL, function() {
before(async function() {
await setup.runGreenwoodCommand('build');
});

runSmokeTest(['public', 'index', 'not-found', 'hello'], LABEL);

describe('Banner Plugin', function() {
let bundleFile;

beforeEach(async function() {
const dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, 'index.html'));
const scriptTags = dom.window.document.querySelectorAll('body script');
const bundleScripts = Array.prototype.slice.call(scriptTags).filter(script => {
const src = script.src;

return src.indexOf('index.') >= 0 && src.indexOf('.bundle.js') >= 0;
});

bundleFile = bundleScripts[0].src.replace('file:///', '');
});

it('should have the banner text in index.js', function() {
const fileContents = fs.readFileSync(path.resolve(this.context.publicDir, bundleFile), 'utf8');

expect(fileContents).to.contain(mockBanner);
});
});
});

after(function() {
setup.teardownTestBed();
});

});
13 changes: 13 additions & 0 deletions packages/cli/test/cases/build.plugins-webpack/greenwood.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { version } = require('../../../package.json');
const webpack = require('webpack');

module.exports = {

plugins: [{
type: 'webpack',
provider: () => {
return new webpack.BannerPlugin(`My Banner - v${version}`);
}
}]

};
11 changes: 8 additions & 3 deletions www/components/shelf/plugins.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
[
{
"index": 0,
"name": "Composite Plugins",
"path": "/plugins/composite-plugins"
},
{
"index": 1,
"name": "Index Hooks",
"path": "/plugins/index-hooks"
},
{
"index": 1,
"name": "Composite Plugins",
"path": "/plugins/composite-plugins"
"index": 2,
"name": "Webpack Plugins",
"path": "/plugins/webpack"
}
]
36 changes: 36 additions & 0 deletions www/pages/plugins/webpack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Webpack Plugins

> This is an expiremental API! [YMMV](http://onlineslangdictionary.com/meaning-definition-of/your-mileage-may-vary)
Although Greenwood aims to provide a complete development environment out of the box, we recognize that for those users who are comfortable with webpack and want to introduce customizations using actual webpack plugins.


## Usage
Below is an example of using the [Banner Plugin](https://webpack.js.org/plugins/banner-plugin/) to add text to each file generated by webpack in _greenwood.config.js_.

```render javascript
const { version } = require('package.json');
module.exports = {
...
plugins: [{
type: 'webpack',
provider: () => {
return new webpack.BannerPlugin(\`My App v${version}\`);
}
}]
}
```

## Compatibility
Although we can't promise all webpack plugins will work, we will try and document which ones we have had success with either as part of the CLI or one of our composite plugins.
| Name | Notes |
|---|---|
| [Banner Plugin](https://webpack.js.org/plugins/banner-plugin/) | Used as an example in unit tests for `@greenwood/cli`. |


## Known Issues
Currently there are no known issues (yet). 🤞

0 comments on commit 019a751

Please sign in to comment.