Skip to content

Commit 793dde2

Browse files
author
benholloway
committed
reimplemented for extensibility and multi-compiler separation
1 parent 95a9ac6 commit 793dde2

18 files changed

+558
-239
lines changed

config/add/browser-sync.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
5+
var glob = require('glob'),
6+
BrowserSyncPlugin = require('browser-sync-webpack-plugin');
7+
8+
/**
9+
* Add browser-sync feature.
10+
* @this {Config} A webpack-configurator instance
11+
* @param {string} directory Base directory for the server (should point to your compiled application)
12+
* @param {number} port Server port
13+
* @returns {Config} The given webpack-configurator instance
14+
*/
15+
function browserSync(directory, port) {
16+
/* jshint validthis:true */
17+
return this
18+
.plugin('browser-sync', BrowserSyncPlugin, [{
19+
host : 'localhost',
20+
port : port,
21+
server: {
22+
baseDir: directory,
23+
routes : {'/': ''}
24+
},
25+
open : false
26+
}]);
27+
}
28+
29+
module.exports = browserSync;

config/add/clean.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
var CleanPlugin = require('clean-webpack-plugin');
4+
5+
/**
6+
* Remove the given directory at compilation start.
7+
* @this {Config} A webpack-configurator instance
8+
* @param {string} directory A directory to remove at start of compilation
9+
* @returns {Config} The given webpack-configurator instance
10+
*/
11+
function clean(directory) {
12+
/* jshint validthis:true */
13+
return this
14+
.plugin('clean', CleanPlugin, [
15+
directory,
16+
{root: process.cwd(), verbose: false}
17+
]);
18+
}
19+
20+
module.exports = clean;

config/add/common.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
5+
var webpack = require('webpack'),
6+
ExtractTextPlugin = require('extract-text-webpack-plugin'),
7+
BowerWebpackPlugin = require('bower-webpack-plugin'),
8+
EntryGeneratorPlugin = require('entry-generator-webpack-plugin'),
9+
OmitTildePlugin = require('omit-tilde-webpack-plugin');
10+
11+
/**
12+
* Add common features.
13+
* @this {Config} A webpack-configurator instance
14+
* @param {string} loaderRoot The base path in which to locate loaders
15+
* @param {object} globals A hash of globals
16+
* @returns {Config} The given webpack-configurator instance
17+
*/
18+
function common(loaderRoot, globals) {
19+
/* jshint validthis:true */
20+
return this
21+
.merge({
22+
context : process.cwd(),
23+
cache : true,
24+
devtool : 'source-map',
25+
entry : {
26+
vendor: './app/vendor.js'
27+
},
28+
output : {
29+
filename : '[name].[chunkhash].js',
30+
chunkFilename : '[name].[chunkhash].js',
31+
devtoolModuleFilenameTemplate : '[resource-path]',
32+
devtoolFallbackModuleFilenameTemplate: '[resource-path]?[hash]'
33+
},
34+
resolve : {
35+
alias : {
36+
npm: path.resolve('node_modules')
37+
},
38+
root : path.resolve('bower_components'),
39+
fallback: path.resolve('node_modules')
40+
},
41+
resolveLoader: {
42+
root : loaderRoot,
43+
fallback: path.resolve('node_modules')
44+
},
45+
node : {
46+
fs: 'empty'
47+
}
48+
})
49+
50+
// before compile
51+
.preLoader('linting', {
52+
test : /\.js$/i,
53+
exclude: /[\\\/](node_modules|bower_components)[\\\/]/i,
54+
loader : 'jshint'
55+
})
56+
57+
// some obscure modules like to 'require()' angular, but bower angular does not export anything
58+
.loader('export-angular', {
59+
test : /[\\\/]angular\.js$/i,
60+
include: /[\\\/]bower_components[\\\/]/i,
61+
loader : 'exports?angular'
62+
})
63+
64+
// supported file types
65+
.loader('css', {
66+
test : /\.css$/i,
67+
loader: ExtractTextPlugin.extract('css?minimize&sourceMap!resolve-url?sourceMap')
68+
})
69+
.loader('sass', {
70+
test : /\.scss$/i,
71+
loader: ExtractTextPlugin.extract('css?minimize&sourceMap!resolve-url?sourceMap!sass?sourceMap')
72+
})
73+
.loader('image', {
74+
test : /\.(jpe?g|png|gif|svg)([#?].*)?$/i,
75+
loaders: [
76+
'file?hash=sha512&digest=hex&name=[hash].[ext]',
77+
'image-webpack?optimizationLevel=7&interlaced=false'
78+
]
79+
})
80+
.loader('woff', {
81+
test : /\.woff2?([#?].*)?$/i,
82+
loader: 'url?limit=10000&mimetype=application/font-woff&name=[hash].[ext]'
83+
})
84+
.loader('font', {
85+
test : /\.(eot|ttf|ico|otf)([#?].*)?$/i,
86+
loader: 'file?name=[hash].[ext]'
87+
})
88+
.loader('js-bower', {
89+
test : /\.js$/i,
90+
include: /[\\\/]bower_components[\\\/]/i,
91+
loaders: [
92+
'sourcemap-sources?format=outputRelative',
93+
'ng-annotate?sourceMap'
94+
]
95+
})
96+
.loader('js', {
97+
test : /\.js$/i,
98+
exclude: /[\\\/](bower_components|webpack|css-loader)[\\\/]/i,
99+
loaders: [
100+
'sourcemap-sources?format=projectRelative',
101+
'ng-annotate?sourceMap',
102+
'sourcemap-sources?format=absolute', // fix ng-annotate source maps in Windows but tweaking incoming map
103+
'nginject?sourceMap&deprecate&singleQuote',
104+
'babel?sourceMap&ignore=buffer&compact=false'
105+
// https://github.com/feross/buffer/issues/79
106+
// http://stackoverflow.com/a/29857361/5535360
107+
]
108+
})
109+
.loader('html', {
110+
test : /\.html?$/i,
111+
loader: 'html?removeComments=false&attrs=img:src link:href'
112+
})
113+
.loader('json', {
114+
test : /\.json$/i,
115+
loader: 'json'
116+
})
117+
118+
// bower
119+
.plugin('generate-vendor', EntryGeneratorPlugin, [
120+
'./app/vendor.js',
121+
EntryGeneratorPlugin.bowerDependenciesSource()
122+
])
123+
.plugin('omit-tilde', OmitTildePlugin, [{
124+
include : ['package.json', 'bower.json'],
125+
deprecate: true
126+
}])
127+
.plugin('bower', BowerWebpackPlugin, [{
128+
includes : /\.((js|css)|(woff2?|eot|ttf|otf)([#?].*)?)$/i,
129+
searchResolveModulesDirectories: false
130+
}])
131+
132+
// globals
133+
.plugin('provide', webpack.ProvidePlugin, [globals])
134+
135+
// output, chunking, optimisation
136+
.plugin('extract-text', ExtractTextPlugin, [
137+
undefined,
138+
'[name].[contenthash].css',
139+
{allChunks: true}
140+
])
141+
.plugin('commons', webpack.optimize.CommonsChunkPlugin, [{
142+
name : 'vendor',
143+
minChunks: Infinity
144+
}])
145+
.plugin('dedupe', webpack.optimize.DedupePlugin)
146+
.plugin('occurence-order', webpack.optimize.OccurenceOrderPlugin);
147+
}
148+
149+
module.exports = common;

config/add/composition.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
5+
var IndexHTMLPlugin = require('indexhtml-webpack-plugin'),
6+
GulpInjectPlugin = require('gulp-inject-webpack-plugin');
7+
8+
/**
9+
* Detect all compositions in the given base directory.
10+
* @this {Config} A webpack-configurator instance
11+
* @param {{directory:string, htmlFiles:Array, indexFiles:Array}} item A composition item
12+
* @returns {Config} The given webpack-configurator instance
13+
*/
14+
function composition(item) {
15+
/* jshint validthis:true */
16+
return this
17+
.merge({
18+
entry: {
19+
'index-html': item.htmlFiles,
20+
index : item.indexFiles
21+
}
22+
})
23+
.plugin('index-html', IndexHTMLPlugin, [
24+
'index-html',
25+
'index.html'
26+
])
27+
.plugin('gulp-inject', GulpInjectPlugin, [
28+
'index-html',
29+
['manifest.json', 'vendor', /^vendor\./, 'index'],
30+
{relative: true}
31+
]);
32+
}
33+
34+
module.exports = composition;

config/add/conditionals.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
var webpack = require('webpack');
4+
5+
/**
6+
* Add compiler conditionals.
7+
* @this {Config} A webpack-configurator instance
8+
* @param {object} flags A hash of flags to use approximate compiler conditionals
9+
* @returns {Config} The given webpack-configurator instance
10+
*/
11+
function conditionals(flags) {
12+
/* jshint validthis:true */
13+
return this
14+
.plugin('conditionals', webpack.ProvidePlugin, [flags]);
15+
}
16+
17+
module.exports = conditionals;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
var ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
4+
5+
/**
6+
* Minimise changes in asset hashing by externalising the chunk manifest.
7+
* Required for long term caching of assets.
8+
* @this {Config} A webpack-configurator instance
9+
* @returns {Config} The given webpack-configurator instance
10+
*/
11+
function externalChunkManifest() {
12+
/* jshint validthis:true */
13+
return this
14+
.plugin('chunk-manifest', ChunkManifestPlugin);
15+
}
16+
17+
module.exports = externalChunkManifest;

config/add/minification.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
var ESManglePlugin = require('esmangle-webpack-plugin');
4+
5+
/**
6+
* Minify javascript where enabled.
7+
* @this {Config} A webpack-configurator instance
8+
* @param {boolean} enabled Determines whether minification is enabled
9+
* @returns {Config} The given webpack-configurator instance
10+
*/
11+
function minification(enabled) {
12+
/* jshint validthis:true */
13+
if (enabled) {
14+
this
15+
.plugin('minification', ESManglePlugin, [
16+
{exclude: /test.\w+.js$/i}
17+
]);
18+
}
19+
return this;
20+
}
21+
22+
module.exports = minification;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
var EntryGeneratorPlugin = require('entry-generator-webpack-plugin');
4+
5+
/**
6+
* Locate all specification files and generate a file that require()s them all.
7+
* @this {Config} A webpack-configurator instance
8+
* @param {string} outputFile The file that will be written
9+
* @param {string} testGlob A glob for all specification files
10+
* @returns {Config} The given webpack-configurator instance
11+
*/
12+
function testSuiteGeneration(outputFile, testGlob) {
13+
/* jshint validthis:true */
14+
return this
15+
.plugin('generate-test', EntryGeneratorPlugin, [
16+
outputFile,
17+
[
18+
EntryGeneratorPlugin.bowerDevDependenciesSource(),
19+
EntryGeneratorPlugin.globSource(testGlob, {
20+
ignore: '**/{node_modules,bower_components,app*}/**'
21+
})
22+
]
23+
]);
24+
}
25+
26+
module.exports = testSuiteGeneration;

config/app.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
5+
var createConfigurator = require('../lib/create-configurator'),
6+
listCompositions = require('../lib/list-compositions');
7+
8+
// TODO doctag
9+
function app(options) {
10+
11+
// there may be any number of compositions in subdirectories
12+
return listCompositions(options.appDir)
13+
.map(eachComposition);
14+
15+
function eachComposition(composition, i) {
16+
var buildDir = path.join(options.buildDir, composition.directory),
17+
config = createConfigurator({
18+
addCommon : require('./add/common'),
19+
addBrowserSync : require('./add/browser-sync'),
20+
addClean : require('./add/clean'),
21+
addComposition : require('./add/composition'),
22+
addConditionals: require('./add/conditionals'),
23+
addMinification: require('./add/minification')
24+
})
25+
.addCommon(path.resolve(__dirname, '..', 'node_modules'), options.globals)
26+
.addClean(buildDir)
27+
.addComposition(composition)
28+
.addConditionals({
29+
TEST : false,
30+
DEBUG : true,
31+
RELEASE: false
32+
})
33+
.addMinification(!options.unminified)
34+
.merge({
35+
output: {
36+
path: path.resolve(buildDir)
37+
}
38+
});
39+
40+
// we only need to create a server for the base composition
41+
return (i === 0) ? config.addBrowserSync(buildDir, options.port) : config;
42+
}
43+
}
44+
45+
module.exports = app;

0 commit comments

Comments
 (0)