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

Commit

Permalink
feat: Replace Gulp with Webpack (and npm scripts)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mischah committed Feb 15, 2018
1 parent 57219c3 commit b91adea
Show file tree
Hide file tree
Showing 49 changed files with 10,837 additions and 14,260 deletions.
11 changes: 10 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
{
"extends": "baumeister"
"extends": "baumeister",
"overrides": [
{
"files": ["build/*.js"],
"rules": {
"no-console": "off",
"unicorn/no-process-exit": "off"
}
}
]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ src/assets/css
.browserify-cache-vendor.json
coverage
.metalsmith-build
.eslintcache
.webpack-stats.json
.webpack-assets.json

### Dev ###
*.sublime-project
Expand Down
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ node_js:
- 8
- node
script:
- npm run dev
- rm -rf server
- npm run build
- npm run build:dev
notifications:
webhooks:
urls:
Expand Down
455 changes: 200 additions & 255 deletions README.md

Large diffs are not rendered by default.

28 changes: 18 additions & 10 deletions baumeister.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
{
"useHandlebars": true,
"purifyCSS": {
"usePurifyCSS": false,
"whitelist": [
"*navbar*",
"*modal*",
"*dropdown*",
"*carousel*",
"*tooltip*",
"open",
"fade",
"collapse",
"collapsing",
"in"
]
},
"generateBanners": false,
"bundleExternalJS": [
"jquery",
"bootstrap"
],
"cacheBusting": true,
"vendor": {
"bundleCSS": [],
"includeStaticFiles": []
},
"webpack": {
"DefinePlugin": {
"dev": {},
"prod": {
"process.env": {
"NODE_ENV": "'production'"
}
}
"development": {},
"production": {}
},
"ProvidePlugin": {
"$": "jquery",
Expand Down
35 changes: 35 additions & 0 deletions build/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const configFile = require('../baumeister.json');

/**
* Boolean flag to set when using handlebars instead of plain HTML files in `src`.
*/
export const useHandlebars = configFile.useHandlebars;

/**
* Flag for generating banners on on top of dist files (CSS & JS).
*/
export const generateBanners = configFile.generateBanners;

export const mainDirectories = {
dev: '../server/',
prod: '../dist/',
src: '../src'
};

export const settings = {
sources: {
handlebars: './src/handlebars/',
app: './src/app/',
appTemplates: {
directory: './src/app',
files: '**/*.html'
},
assets: './src/assets'
},
destinations: {
handlebars: './.metalsmith-build',
assets: 'assets',
appTemplates: 'app',
vendorFiles: 'assets/vendor'
}
};
103 changes: 103 additions & 0 deletions build/handlebars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import path from 'path';
import fs from 'fs';
import chalk from 'chalk';
import logSymbols from 'log-symbols';
import metalsmith from 'metalsmith';
import layouts from 'metalsmith-layouts';
import inPlace from 'metalsmith-in-place';
import registerHelpers from 'metalsmith-register-helpers';
import registerPartials from 'metalsmith-discover-partials';
import filter from 'metalsmith-filter';
import globby from 'globby';
import perfy from 'perfy';
import {stripIndents} from 'common-tags';

import {settings, useHandlebars} from './config';

perfy.start('build', false);

if (!useHandlebars) {
process.exit(0);
}

metalsmith(__dirname)
// Source directory
.source('../src')

// Destination directory
.destination(path.join(__dirname, '../', settings.destinations.handlebars))

// Clean destination before
.clean(true)

// Register Handlebars helpers
.use(registerHelpers({
directory: path.join(__dirname, '../', settings.sources.handlebars, 'helpers')
}))

// Register Handlebars partials
.use(registerPartials({
directory: path.join(__dirname, '../', settings.sources.handlebars, 'partials'),
pattern: /\.hbs$/
}))

// Wrap layouts around content pages
.use(layouts({
directory: path.join(__dirname, '../', settings.sources.handlebars, 'layouts'),
default: 'default.hbs',
pattern: '*.hbs'
}))

// Render handlebars content pages
.use(inPlace({
engineOptions: {
pattern: '*.hbs',
partials: path.join(__dirname, '../', settings.sources.handlebars, 'partials')
}
}))

// Only build HTML files
.use(filter('*.html'))

// Finally build files
.build(err => {

// Handle build errors
if (err) {
console.log(stripIndents`
${logSymbols.error} Handlebars build failed:
${chalk.red.bold(err.message)}
`);
process.exit(1);

// Handle successful build
} else {
/**
* NOTE:
* We need to backdate the generated files by ten seconds until
* https://github.com/webpack/watchpack/issues/25 is fixed.
* Otherwise we would have some uneeded rebuilds when starting webpack in
* watch mode or starting the webpack dev server.
*/
const f = path.resolve(__dirname, '../', settings.destinations.handlebars);
const now = Date.now() / 1000;
const then = now - 10;
globby(f + '/**/*.html')
.then(files => {
files.forEach(file => {
fs.utimes(file, then, then, (err) => {
if (err) {
console.error(err);
}
console.log(
logSymbols.success,
` Finished ${chalk.blue.bold('Handlebars build')} after`,
chalk.yellow.bold(perfy.end('build').time >= 1 ? `${Math.round(perfy.end('build').time * 100) / 100} s` : `${Math.round(perfy.end('build').milliseconds)} ms`),
'\n'
);
process.exit(0);
});
});
});
}
});
142 changes: 142 additions & 0 deletions build/webpack.base.babel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import path from 'path';
import chalk from 'chalk';
import globby from 'globby';
import webpack from 'webpack';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import WebpackAssetsManifest from 'webpack-assets-manifest';
import minimist from 'minimist';
import {stripIndents} from 'common-tags';

import {settings, useHandlebars} from './config';
const configFile = require('../baumeister.json');

const cliFlags = minimist(process.argv.slice(2));
const isDevMode = process.env.NODE_ENV === 'development';
const buildTarget = isDevMode ? ' Development ' : ' Production ';

const manifest = new WebpackAssetsManifest({
output: path.resolve('.webpack-assets.json')
});

const generateCssFile = new ExtractTextPlugin({
filename: configFile.cacheBusting && !isDevMode ? 'assets/css/[name].[chunkhash].bundle.css' : 'assets/css/[name].bundle.css'
});

const copyVendorFiles = configFile.vendor.includeStaticFiles.map(glob => {
return {
from: glob,
context: 'node_modules',
to: settings.destinations.vendorFiles
};
});

const getVendorCSS = function () {
// Return flattened array of resolved globs from baumeister.json
const vendorCSS = [].concat(...configFile.vendor.bundleCSS.map(glob => globby.sync(`./node_modules/${glob}`)));
if (!vendorCSS.length) {
return false;
}
return {vendor: vendorCSS};
};

if (!cliFlags.json) {
console.log(chalk.yellow(stripIndents`Build target: ${chalk.bold.inverse(buildTarget)}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`));
}

module.exports = (options) => ({
devServer: options.devServer,
entry: {
app: `${settings.sources.app}index.js`,
...getVendorCSS()
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: path.resolve(__dirname, '../', settings.sources.app),
loader: 'babel-loader', options: {sourceMap: true}
},
{
test: /\.css$/,
use: generateCssFile.extract({
use: [
{loader: 'css-loader', options: {sourceMap: true}}
]
})
},
{
test: /\.scss$/,
use: generateCssFile.extract({
use: [
{loader: 'css-loader', options: {sourceMap: true}},
{loader: 'postcss-loader', options:
{
sourceMap: true,
config: {
ctx: {
usePurifyCSS: configFile.purifyCSS.usePurifyCSS,
cssnano: {
discardComments: {
removeAll: true
}
},
autoprefixer: {
browsers: [
'> 1%',
'last 3 version',
'ie 8',
'ie 9',
'Firefox ESR',
'Opera 12.1'
]
}
}
}
}
},
{loader: 'sass-loader', options: {sourceMap: true}}
]
})
}
]
},
output: options.output,
plugins: [
manifest,
generateCssFile,
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => /node_modules/.test(module.resource)
}),
new webpack.ProvidePlugin({...configFile.webpack.ProvidePlugin}),
new CopyWebpackPlugin([
{
from: '**/*.html',
context: useHandlebars ? settings.destinations.handlebars : './src',
transform(content) {
return content.toString().replace(/@@(.*\.css|.*\.js)/g, (match, $1) => {
if (!($1 in manifest.assets)) {
return `<!-- No ${$1} to be bundled -->`;
}
return /\.css/g.test($1) ? `<link href="${manifest.assets[$1]}" rel="stylesheet">` : `<script src="${manifest.assets[$1]}"></script>`;
});
}
},
{
from: '**/*',
context: settings.sources.assets,
to: settings.destinations.assets,
ignore: ['scss/**']
},
...copyVendorFiles
]),
...options.plugins
],
stats: {
timings: true,
version: false,
hash: false
}
});
23 changes: 23 additions & 0 deletions build/webpack.dev.babel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import path from 'path';
import webpack from 'webpack';

import {mainDirectories} from './config';
const configFile = require('../baumeister.json');

module.exports = require('./webpack.base.babel')({
devServer: {
contentBase: path.join(__dirname, mainDirectories.dev),
port: 3000,
overlay: true
},
output: {
path: path.join(__dirname, mainDirectories.dev),
filename: 'app/[name].bundle.js'
},
plugins: [
new webpack.SourceMapDevToolPlugin({
columns: false
}),
new webpack.DefinePlugin({...configFile.webpack.DefinePlugin.development})
]
});
Loading

0 comments on commit b91adea

Please sign in to comment.