Skip to content
This repository was archived by the owner on Oct 15, 2021. It is now read-only.

Commit b91adea

Browse files
committed
feat: Replace Gulp with Webpack (and npm scripts)
BREAKING CHANGE: Gulp and all the tasks are gone. But most of the npm scripts still do what they did before. Here are the main scripts needed for developing and building your project. | Command | Description | | ----------------------- | --- | | `npm start` | *Builds for development, starts a webserver, watches files for changes, rebuilds incremental and reloads your browser.* | | `npm test` | *Lints your JavaScript files and runs unit test via the Jest CLI.* | | `npm run test:watch` | *Runs unit test with Jests watch option.* | | `npm run build` | *Builds for production to `dist` directory.* | | `npm run build:check` | *Starts a static fileserver serving the `dist` directory.* | | `npm run build:analyze` | *Starts »Webpack Bundle Analyzer« to visualize size of Webpack output files* | See package.json scripts section for all available scripts. The polyfills bundle is gone and the references to the bundles in default.hbs has changed to: <!-- Bundled vendor CSS files --> @@vendor.css <!-- Our compiled and merged Sass files --> @@app.css <!-- Vendor JS --> @@vendor.js <!-- Own JS --> @@app.js # Conflicts: # gulp/config.js # gulp/tasks/handlebars.js # gulpfile.babel.js # package-lock.json # package.json # webpack.config.js
1 parent 57219c3 commit b91adea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+10837
-14260
lines changed

.eslintrc.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
{
2-
"extends": "baumeister"
2+
"extends": "baumeister",
3+
"overrides": [
4+
{
5+
"files": ["build/*.js"],
6+
"rules": {
7+
"no-console": "off",
8+
"unicorn/no-process-exit": "off"
9+
}
10+
}
11+
]
312
}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ src/assets/css
1414
.browserify-cache-vendor.json
1515
coverage
1616
.metalsmith-build
17+
.eslintcache
18+
.webpack-stats.json
19+
.webpack-assets.json
1720

1821
### Dev ###
1922
*.sublime-project

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ node_js:
55
- 8
66
- node
77
script:
8-
- npm run dev
9-
- rm -rf server
108
- npm run build
9+
- npm run build:dev
1110
notifications:
1211
webhooks:
1312
urls:

README.md

Lines changed: 200 additions & 255 deletions
Large diffs are not rendered by default.

baumeister.json

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
{
22
"useHandlebars": true,
3+
"purifyCSS": {
4+
"usePurifyCSS": false,
5+
"whitelist": [
6+
"*navbar*",
7+
"*modal*",
8+
"*dropdown*",
9+
"*carousel*",
10+
"*tooltip*",
11+
"open",
12+
"fade",
13+
"collapse",
14+
"collapsing",
15+
"in"
16+
]
17+
},
318
"generateBanners": false,
4-
"bundleExternalJS": [
5-
"jquery",
6-
"bootstrap"
7-
],
19+
"cacheBusting": true,
820
"vendor": {
921
"bundleCSS": [],
1022
"includeStaticFiles": []
1123
},
1224
"webpack": {
1325
"DefinePlugin": {
14-
"dev": {},
15-
"prod": {
16-
"process.env": {
17-
"NODE_ENV": "'production'"
18-
}
19-
}
26+
"development": {},
27+
"production": {}
2028
},
2129
"ProvidePlugin": {
2230
"$": "jquery",

build/config.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const configFile = require('../baumeister.json');
2+
3+
/**
4+
* Boolean flag to set when using handlebars instead of plain HTML files in `src`.
5+
*/
6+
export const useHandlebars = configFile.useHandlebars;
7+
8+
/**
9+
* Flag for generating banners on on top of dist files (CSS & JS).
10+
*/
11+
export const generateBanners = configFile.generateBanners;
12+
13+
export const mainDirectories = {
14+
dev: '../server/',
15+
prod: '../dist/',
16+
src: '../src'
17+
};
18+
19+
export const settings = {
20+
sources: {
21+
handlebars: './src/handlebars/',
22+
app: './src/app/',
23+
appTemplates: {
24+
directory: './src/app',
25+
files: '**/*.html'
26+
},
27+
assets: './src/assets'
28+
},
29+
destinations: {
30+
handlebars: './.metalsmith-build',
31+
assets: 'assets',
32+
appTemplates: 'app',
33+
vendorFiles: 'assets/vendor'
34+
}
35+
};

build/handlebars.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import path from 'path';
2+
import fs from 'fs';
3+
import chalk from 'chalk';
4+
import logSymbols from 'log-symbols';
5+
import metalsmith from 'metalsmith';
6+
import layouts from 'metalsmith-layouts';
7+
import inPlace from 'metalsmith-in-place';
8+
import registerHelpers from 'metalsmith-register-helpers';
9+
import registerPartials from 'metalsmith-discover-partials';
10+
import filter from 'metalsmith-filter';
11+
import globby from 'globby';
12+
import perfy from 'perfy';
13+
import {stripIndents} from 'common-tags';
14+
15+
import {settings, useHandlebars} from './config';
16+
17+
perfy.start('build', false);
18+
19+
if (!useHandlebars) {
20+
process.exit(0);
21+
}
22+
23+
metalsmith(__dirname)
24+
// Source directory
25+
.source('../src')
26+
27+
// Destination directory
28+
.destination(path.join(__dirname, '../', settings.destinations.handlebars))
29+
30+
// Clean destination before
31+
.clean(true)
32+
33+
// Register Handlebars helpers
34+
.use(registerHelpers({
35+
directory: path.join(__dirname, '../', settings.sources.handlebars, 'helpers')
36+
}))
37+
38+
// Register Handlebars partials
39+
.use(registerPartials({
40+
directory: path.join(__dirname, '../', settings.sources.handlebars, 'partials'),
41+
pattern: /\.hbs$/
42+
}))
43+
44+
// Wrap layouts around content pages
45+
.use(layouts({
46+
directory: path.join(__dirname, '../', settings.sources.handlebars, 'layouts'),
47+
default: 'default.hbs',
48+
pattern: '*.hbs'
49+
}))
50+
51+
// Render handlebars content pages
52+
.use(inPlace({
53+
engineOptions: {
54+
pattern: '*.hbs',
55+
partials: path.join(__dirname, '../', settings.sources.handlebars, 'partials')
56+
}
57+
}))
58+
59+
// Only build HTML files
60+
.use(filter('*.html'))
61+
62+
// Finally build files
63+
.build(err => {
64+
65+
// Handle build errors
66+
if (err) {
67+
console.log(stripIndents`
68+
${logSymbols.error} Handlebars build failed:
69+
${chalk.red.bold(err.message)}
70+
`);
71+
process.exit(1);
72+
73+
// Handle successful build
74+
} else {
75+
/**
76+
* NOTE:
77+
* We need to backdate the generated files by ten seconds until
78+
* https://github.com/webpack/watchpack/issues/25 is fixed.
79+
* Otherwise we would have some uneeded rebuilds when starting webpack in
80+
* watch mode or starting the webpack dev server.
81+
*/
82+
const f = path.resolve(__dirname, '../', settings.destinations.handlebars);
83+
const now = Date.now() / 1000;
84+
const then = now - 10;
85+
globby(f + '/**/*.html')
86+
.then(files => {
87+
files.forEach(file => {
88+
fs.utimes(file, then, then, (err) => {
89+
if (err) {
90+
console.error(err);
91+
}
92+
console.log(
93+
logSymbols.success,
94+
` Finished ${chalk.blue.bold('Handlebars build')} after`,
95+
chalk.yellow.bold(perfy.end('build').time >= 1 ? `${Math.round(perfy.end('build').time * 100) / 100} s` : `${Math.round(perfy.end('build').milliseconds)} ms`),
96+
'\n'
97+
);
98+
process.exit(0);
99+
});
100+
});
101+
});
102+
}
103+
});

build/webpack.base.babel.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import path from 'path';
2+
import chalk from 'chalk';
3+
import globby from 'globby';
4+
import webpack from 'webpack';
5+
import CopyWebpackPlugin from 'copy-webpack-plugin';
6+
import ExtractTextPlugin from 'extract-text-webpack-plugin';
7+
import WebpackAssetsManifest from 'webpack-assets-manifest';
8+
import minimist from 'minimist';
9+
import {stripIndents} from 'common-tags';
10+
11+
import {settings, useHandlebars} from './config';
12+
const configFile = require('../baumeister.json');
13+
14+
const cliFlags = minimist(process.argv.slice(2));
15+
const isDevMode = process.env.NODE_ENV === 'development';
16+
const buildTarget = isDevMode ? ' Development ' : ' Production ';
17+
18+
const manifest = new WebpackAssetsManifest({
19+
output: path.resolve('.webpack-assets.json')
20+
});
21+
22+
const generateCssFile = new ExtractTextPlugin({
23+
filename: configFile.cacheBusting && !isDevMode ? 'assets/css/[name].[chunkhash].bundle.css' : 'assets/css/[name].bundle.css'
24+
});
25+
26+
const copyVendorFiles = configFile.vendor.includeStaticFiles.map(glob => {
27+
return {
28+
from: glob,
29+
context: 'node_modules',
30+
to: settings.destinations.vendorFiles
31+
};
32+
});
33+
34+
const getVendorCSS = function () {
35+
// Return flattened array of resolved globs from baumeister.json
36+
const vendorCSS = [].concat(...configFile.vendor.bundleCSS.map(glob => globby.sync(`./node_modules/${glob}`)));
37+
if (!vendorCSS.length) {
38+
return false;
39+
}
40+
return {vendor: vendorCSS};
41+
};
42+
43+
if (!cliFlags.json) {
44+
console.log(chalk.yellow(stripIndents`Build target: ${chalk.bold.inverse(buildTarget)}
45+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`));
46+
}
47+
48+
module.exports = (options) => ({
49+
devServer: options.devServer,
50+
entry: {
51+
app: `${settings.sources.app}index.js`,
52+
...getVendorCSS()
53+
},
54+
module: {
55+
rules: [
56+
{
57+
test: /\.(js|jsx)$/,
58+
include: path.resolve(__dirname, '../', settings.sources.app),
59+
loader: 'babel-loader', options: {sourceMap: true}
60+
},
61+
{
62+
test: /\.css$/,
63+
use: generateCssFile.extract({
64+
use: [
65+
{loader: 'css-loader', options: {sourceMap: true}}
66+
]
67+
})
68+
},
69+
{
70+
test: /\.scss$/,
71+
use: generateCssFile.extract({
72+
use: [
73+
{loader: 'css-loader', options: {sourceMap: true}},
74+
{loader: 'postcss-loader', options:
75+
{
76+
sourceMap: true,
77+
config: {
78+
ctx: {
79+
usePurifyCSS: configFile.purifyCSS.usePurifyCSS,
80+
cssnano: {
81+
discardComments: {
82+
removeAll: true
83+
}
84+
},
85+
autoprefixer: {
86+
browsers: [
87+
'> 1%',
88+
'last 3 version',
89+
'ie 8',
90+
'ie 9',
91+
'Firefox ESR',
92+
'Opera 12.1'
93+
]
94+
}
95+
}
96+
}
97+
}
98+
},
99+
{loader: 'sass-loader', options: {sourceMap: true}}
100+
]
101+
})
102+
}
103+
]
104+
},
105+
output: options.output,
106+
plugins: [
107+
manifest,
108+
generateCssFile,
109+
new webpack.optimize.CommonsChunkPlugin({
110+
name: 'vendor',
111+
minChunks: module => /node_modules/.test(module.resource)
112+
}),
113+
new webpack.ProvidePlugin({...configFile.webpack.ProvidePlugin}),
114+
new CopyWebpackPlugin([
115+
{
116+
from: '**/*.html',
117+
context: useHandlebars ? settings.destinations.handlebars : './src',
118+
transform(content) {
119+
return content.toString().replace(/@@(.*\.css|.*\.js)/g, (match, $1) => {
120+
if (!($1 in manifest.assets)) {
121+
return `<!-- No ${$1} to be bundled -->`;
122+
}
123+
return /\.css/g.test($1) ? `<link href="${manifest.assets[$1]}" rel="stylesheet">` : `<script src="${manifest.assets[$1]}"></script>`;
124+
});
125+
}
126+
},
127+
{
128+
from: '**/*',
129+
context: settings.sources.assets,
130+
to: settings.destinations.assets,
131+
ignore: ['scss/**']
132+
},
133+
...copyVendorFiles
134+
]),
135+
...options.plugins
136+
],
137+
stats: {
138+
timings: true,
139+
version: false,
140+
hash: false
141+
}
142+
});

build/webpack.dev.babel.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import path from 'path';
2+
import webpack from 'webpack';
3+
4+
import {mainDirectories} from './config';
5+
const configFile = require('../baumeister.json');
6+
7+
module.exports = require('./webpack.base.babel')({
8+
devServer: {
9+
contentBase: path.join(__dirname, mainDirectories.dev),
10+
port: 3000,
11+
overlay: true
12+
},
13+
output: {
14+
path: path.join(__dirname, mainDirectories.dev),
15+
filename: 'app/[name].bundle.js'
16+
},
17+
plugins: [
18+
new webpack.SourceMapDevToolPlugin({
19+
columns: false
20+
}),
21+
new webpack.DefinePlugin({...configFile.webpack.DefinePlugin.development})
22+
]
23+
});

0 commit comments

Comments
 (0)