is currently readonly. We are migrating to, please continue working there on Monday 14/12. See:

Commit b62785f3 authored by Ate Douma's avatar Ate Douma

TRIVIAL cleanup master

parent 2fe2e69f
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": [
"last 1 Chrome versions",
"last 1 Firefox versions",
"last 1 Safari versions",
"last 1 Edge versions"
"env": {
"development": {
"plugins": [["angularjs-annotate", { "explicitOnly" : true }]]
"production": {
"plugins": [["angularjs-annotate", { "explicitOnly" : true }]]
"test": {
"plugins": [
["angularjs-annotate", { "explicitOnly" : true }],
["istanbul", { "exclude": ["**/*.spec.js", "**/*.spec.ts"]}]
"extends": "airbnb-base",
"env": {
"browser": true,
"jasmine": true
"globals": {
"$": true,
"$j": true,
"angular": true,
"inject": true,
"module": true
"rules": {
"class-methods-use-this": "off",
"global-require": "off",
"linebreak-style": "off",
"max-len": "off",
"no-param-reassign": "off",
"no-prototype-builtins": "off",
"no-restricted-properties": "off",
"no-underscore-dangle": "off",
"import/no-dynamic-require": "off",
"import/no-extraneous-dependencies": ["error", {"devDependencies": ["**/*.spec.js"]}],
"import/prefer-default-export": "off"
"requireCleanWorkingDir": true,
"src": {
"commit": true,
"tag": true,
"push": true
"npm": {
"publish": true,
"tag": "latest",
"access": "public"
"prompt": {
"src": {
"status": false,
"commit": true,
"tag": true,
"push": true,
"release": false,
"publish": true
"pkgFiles": [
"extends": [
"ignoreFiles": "src/vendor.scss",
"rules": {
"selector-type-no-unknown": null,
"no-descending-specificity": null,
"number-leading-zero": "never"
# Changelog & Upgrade notes
## 7.1.2
* Run stylelint on tests with CLI flag --lint
## 7.1.1
* Add dependency on uglify-es@3.3.10 to work around and [CHANNELMGR-1709](
## 7.1.0
* Gulp v4 and removed gulp-util
* When running serve-production HMR should be disabled
* Replaced sasslint with stylelint
* We use the rulesets [stylelint-config-standard]( and [stylelint-config-recommended-scss](
* To use it in your project, replace the file .sass-lint.yml with .stylelintrc and the following contents:
"extends": "./node_modules/@bloomreach/frontend-build/.stylelintrc"
## 7.0.2
* Add build.conf.js option to disable TypeScript
## 7.0.1
* Remove obsolete tslint rules
## 7.0.0
* Node 8 and NPM 5
* Use awesome-typescript-loader
* Make linting optional, disabled by default (add --lint flag to enable linting)
* Add possibility to use Webpack DLL and HardSource plugin for tests
* Fix TypeScript coverage reporting
* Fix colored output for several CLI options
* Optionally disable TypeScript type-checking (add --transpileOnly flag)
## 6.0.5
* Add angularjs-annotate plugin to babel test env
## 6.0.3
* Allow end projects to customize browsers and launchers for karma
* Use release-it to release new versions of frontend-build
## 6.0.0
* Renamed to @bloomreach/frontend-build and published on the npm registry
under the @bloomreach organization scope.
* Add ability to compile Typescript and use Angular with frontend-build
* Rename default expected folder from `src/angularjs/` to `src/app/` to be
able to generate Angular app parts with @angular/cli
## 5.1.0
* Add hash to development files to fix webpack-dev-server issue where changes files would not be reloaded.
* Add cache option using the HardSourcePlugin. Mainly for speeding up development (re)builds, a new cache flag can be passed, e.g.:
`$ npm run start -- --cache`
* Use headless Chrome to run unit tests. Added gulp task 'testDebug' to run tests in normal Chrome (with a head).
* Allow karma port to be customized so users can fire up multiple karma instances
* Simplified webpack output when running tests
* Display error when NPM5 is used.
## 5.0.7
* Added *.css loader so end projects can `require` vendor CSS files, instead of building them from source. This also helps packaging vendor css files in the `vendor` lib file.
* All files required from the **node_modules** folder are now automatically packaged in the `vendor` lib file.
* Webpack module loader code is no longer duplicated and packaged in a separate `manifest` file.
* For production builds all produced files are property cachebusted with a hash based on the file content.
* Fixed production and test sourcemaps
* Bumped Karma to 1.7.0
* Fixed haning process when running `$ yarn run test` or `$ yarn run testOnce`
## 5.0.6
## 5.0.5
* Add sourcemaps for production builds
* Add support for the webpack-bundle-analyzer plugin. This helps with
visualizing the contents of your bundles. It can be triggered on both
the production and development builds by passing the `analyze` commandline flag, e.g.:
`$ yarn run buildDev -- --analyze`
## 5.0.4
* Locked eslint-config-airbnb-base version to 11.1.0.
## 5.0.3
* Ignore no-restricted-properties eslint warnings.
## 5.0.2
## 5.0.1
## 5.0.0
* Updated to webpack 2 official release. This requires some backwards
incompatible changes to custom configuration.
Required to use the '-loader' suffix now when defining loaders.
Please lookup the webpack documentation for more changes / details.
## 4.2.2
* Woff and woff2 files are loaded with the url loader in production.
## 4.2.1
* Allow build.conf.publicPath to be an empty string.
## 4.2.0
* Import SCSS files located in /styles/string/ as CSS string instead of as URL.
## 4.1.1
* Bumped sass-lint to 1.10.2 to support disabling of lint rules in source code.
## 4.1.0
* Import SVGs located in /images/html/ as HTML instead of URLs.
## 4.0.7
* Update README and package.json to point to correct repository
* Add changelog file
This diff is collapsed.
Frontend Build
Copyright 2015-2018 Hippo B.V. (
This product includes software developed by:
Hippo B.V., Amsterdam, The Netherlands (;
The Apache Software Foundation (
NOTICE: Only our own original work is licensed under the terms of the
Apache License Version 2.0. The licenses of some libraries might impose
different redistribution or general licensing terms than those stated in the
Apache License. Users and redistributors are hereby requested to verify these
conditions and agree upon them.
This package, although published as a public package, is only meant to be used
internally at Bloomreach. We offer no support whatsoever to anyone outside
# This is not the branch you're looking for...
# Frontend Build
Frontend build system for frontend apps at Bloomreach.
BloomReach only provides the git trees for the release tags of Hippo CMS, as explained on
- Linting, compiling and optimizing of ES2015+ files
- Linting, compiling and optimizing of Typescript files
- Specific support for Angularjs and Angular apps.
- Run unit tests using the Karma Test Runner and Jasmine framework
- Provide text-summary and html coverage reports over original source code
- Linting, compiling and optimizing of Sass (scss) files
- Loading of html, svg, images and fonts
- Provide sourcemaps to original source code
To checkout the code for a specific release tag, after cloning this repository, use the following:
## Changelog
Release notes are found in the [changelog](
## to show the available tags
## Frontend Build release steps
We use [release-it]( to release to
@bloomreach. A config file is included with preset configuration options.
git tag
Examples of commands:
- Release new minor version: `npm run release-it -- --increment=minor --src.commitMessage="[Relevant JIRA issue] Release %s"`
- Release new pre-release under a npm tag: `npm run release-it -- --increment=prerelease --src.commitMessage="[Relevant JIRA issue] Release %s" --prereleaseId="[relevant prerelease] --npm.tag=["relevant npm tag"]"`
- Non-interactive mode patch version publish: `npm run release-it -- --non-interactive --src.commitMessage="[Relevant JIRA issue] Release %s"`
## to checkout a specific tag
## Webpack build options
You can use the following options as follows: `npm run build -- --<option1> --<option2>`
git checkout <tag name>
- analyze: show bundle content as convenient interactive zoomable treemap [webpack-bundle-analyzer](
- cache: enable module caching with the [HardSourceWebpackPlugin](
- dll: run Webpack (currently only for tests) with the DLL plugin enabled,
note that you need to generate your DLL's prior to this by executing `npm run buildDll`
- lint: run eslint, tslint and sasslint on your code
- profile: adds timing information to the --verbose output, see for more information
- transpileOnly: skip TypeScript type checking, by default it will run in a
forked process
- verbose: get detailed build output information
## to modify a project
If you want to make modifications to a project, for example to create a patch, create a new fork branch from the specific tag like this:
## Webpack DLL's
To improve the build speed for tests, we provide the possibility to use the
Webpack DLL plugin. In short, this will ensure only our own sources are packaged,
and external modules (like angular) will simply be included from node_modules.
To use the DLL setup, we first need to generate the DLL manifest(s): `npm run buildDll`
This will generate a manifest JSON file with a related bundle javascript file.
Now you can run the tests with DLL's: `npm run test -- --dll`
Note: by default, all dependencies in your package.json file are bundled into a single
DLL. To have more finegrained control (change order, exclude modules, etc) you can
specify a `dlls` property in your `build.conf.js` file, e.g.
dlls: {
angularjs: [
angular: [
## Webpack special loader rules
* SVGs located in images/html/ are loaded as strings so they can be used inline
* Sass files in styles/string are loaded as strings so they can be used inline
* Sass files for Angular apps following the convention `*.component.scss` will
be loaded as strings so they can be used inline
## Linting with Codelyzer
The frontend-build tslint.json includes rules provided by Codelyzer because we
copied the tslint config from @angular/cli. However we do not want to dictate
the @angular/core version from frontend-build (@angular/core is a peerDependency
of Codelyzer) so we leave it up to the end project to depend on and implement
codelyzer and its config in tslint.
## Testing
#### Loading HTML, CSS and JSON fixtures
The default Karma setup of frontend-build exposes the
[jasmine-jquery]( module for handling
HTML, CSS and JSON fixtures, as well as provide a set of custom matchers that
simplify validating DOM conditions, e.g. `expect($('#id-name')[0]).toBeInDOM()`.
Fixture files should be defined adjacent to the spec files that use them, or at
least as close as possible. They follow the same naming convention as the spec
files and are named with a `.fixture` suffix, e.g. `cms.login.fixture.html` or
`cms.config.fixture.json`. Karma can be instructed to serve fixture files over
it's HTTP-server by adding a file pattern to the `files` array in the project's
`karma.conf.js`. The default pattern is saved in `cfg.src.fixtures` and matches
`{ pattern: cfg.srcDir + '**/*.fixture.+(js|html|css|json)', included: false}`.
Frontend-build instructs Karma by default to proxy the path
`/spec/javascripts/fixtures/` (which is the default fixtures path of
jasmine-jquery) to `/base/src/app/`. This is a combination of Karma's base
path for serving files over HTTP and the root folder where frontend-build
expects your Angular code to live.
When changing the karma options you can customize the proxy path with the
following options:
* override `cfg.srcDir` in your build.conf.js which changes the default proxy
path from `/base/src/app` to `/base/[your src dir]/app`
* override `cfg.karmaFixtureProxyPath` in your build.conf.js directly
* override `options.proxies` in your karma.conf.js, then you will have to
replicate these two configuration values:
proxies: {
'/spec/javascripts/fixtures/': '[your proxy path]',
'/spec/javascripts/fixtures/json/': '[your proxy path]',
##### Example project setup and code
|- src
|- app
|- main.js
|- main.spec.js
|- main.fixture.html
|- main.fixture.json
|- dialogs
|- dialog.fixture.html
|- dialog.fixture.css
In `main.spec.js` you can then load your fixtures with:
// Load html fixture into the DOM
// from a subfolder
// load css fixture into the DOM
// Load JSON fixture object
var jsonObject = jasmine.getJSONFixtures().load('main.fixture.json');
For more control over the paths you can use the following snippet in your spec files:
beforeEach(function () {
jasmine.getFixtures().fixturesPath = 'base/spec/js/fixtures';
jasmine.getStyleFixtures().fixturesPath = 'base/spec/css/fixtures';
jasmine.getJSONFixtures().fixturesPath = 'base/spec/json/fixtures';
git checkout -b forked-<tag name> <tag name>
For the latter, also see the **Build from Source** documentation at
\ No newline at end of file
* Copyright 2016-2018 Hippo B.V. (
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
* This file contains the variables used in other gulp files
* which defines tasks
* By design, we only put there very generic config values
* which are used in several places to keep good readability
* of the tasks
const path = require('path');
const isString = require('lodash.isstring');
const minimist = require('minimist');
const basePath = process.cwd();
const pjson = require(`${basePath}/package.json`);
function getEnv() {
if (process.env.NODE_ENV === 'development') {
return 'dev';
if (process.env.NODE_ENV === 'test') {
return 'test';
return 'prod';
function requireIfAvailable(name, def) {
try {
return require(name);
} catch (e) {
return def;
const customConf = requireIfAvailable(`${basePath}/build.conf`, {});
exports.custom = customConf;
exports.cli = minimist(process.argv.slice(2), {
default: {
analyze: false,
cache: false,
dll: false,
lint: false,
profile: false,
transpileOnly: false,
verbose: false,
// Typescript transpilation is enabled by default. It can be disabled by setting
// property 'typeScript' to false in ./build.conf.js
exports.typeScript = customConf.hasOwnProperty('typeScript') ? customConf.typeScript : true;
* Export an object representing DLL modules. If none is specified, a single DLL module is
* generated that includes all dependencies from package.json
exports.dlls = customConf.dlls ? customConf.dlls : { vendor: Object.keys(pjson.dependencies) };
exports.regexp = {
htmlExcludes: customConf.htmlExcludes || function noop() {},
htmlSvg: /\/images\/html\/.*\.svg$/,
stringScss: /\/styles\/string\/.*\.scss$/,
angularComponentScss: /.*\.component\.scss$/,
* The main paths of your project handle these with care
const cacheRoot = customConf.cache || `${basePath}/.cache`;
exports.paths = {
cache: `${cacheRoot}/${getEnv()}`,
coverage: customConf.coverage || `${basePath}/coverage`,
dist: customConf.dist || `${basePath}/dist`,
dll: customConf.dll || `${cacheRoot}/dll`,
npmDir: `${basePath}/node_modules`,
publicPath: isString(customConf.publicPath) ? customConf.publicPath : '/',
src: `${basePath}/src`,
tasks: 'gulp_tasks',
* Each entry in exports.paths is exposed in export.path as a helper function
* that returns a file path relative to it, e.g. if exports.paths.src = 'folder/to/src',
* then export.path.src('main', 'index.js') returns '/folder/to/src/main/index.js'
exports.path = {};
Object.keys(exports.paths).forEach((pathName) => {
exports.path[pathName] = function pathJoin(...funcArgs) {
const pathValue = exports.paths[pathName];
const args = [pathValue].concat(funcArgs);
return path.join.apply(this, args);
exports.browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions',
'last 1 Edge versions',
* Copyright 2016-2018 Hippo B.V. (
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
const conf = require('./build.conf');
const webpackTestConf = require('./webpack-test.conf');
const { getServeStats } = require('../conf/webpack.stats');
const karmaFixtureProxyPath = '/base/src/app/';
const customKarma = conf.custom && conf.custom.karma ? conf.custom.karma : {};
const customKarmaFiles = customKarma.files || [];
module.exports = function karmaConfig(config) {
const configuration = {
mime: {
'text/x-typescript': ['ts'],
autoWatchBatchDelay: 300,
port: customKarma.port || 9876,
basePath: conf.paths.basePath,
browsers: customKarma.browsers || [config.debug ? 'Chrome' : 'ChromeHeadless'],
customLaunchers: customKarma.customLaunchers || {},
frameworks: [
exclude: [
files: [
pattern: conf.path.src('**/*.fixture.+(ts|js|html|css|json)'),
included: false,
preprocessors: {
[conf.path.src('index.spec.*')]: [
[conf.path.src('**/!(*fixture).html')]: [
proxies: Object.assign({
'/spec/javascripts/fixtures/': karmaFixtureProxyPath,
'/spec/javascripts/fixtures/json/': karmaFixtureProxyPath,
}, customKarma.proxies),
ngHtml2JsPreprocessor: {
stripPrefix: `${conf.paths.src}/`,
reporters: [
coverageReporter: {
reporters: [
{ type: 'html' },
{ type: 'text-summary' },
dir: conf.path.coverage(),
mochaReporter: {
output: 'minimal',
webpack: webpackTestConf,
webpackMiddleware: {
stats: getServeStats(),
browserConsoleLogOptions: {
level: 'log',
terminal: true,
if (conf.cli.dll) {
// serve .map files for DLL files
pattern: conf.path.dll('*'),
included: false,
watched: false,
// load DLL bundles
configuration.files.unshift(...Object.keys(conf.dlls).reverse().map(dll => conf.path.dll(`${dll}.bundle.js`)));
// use DLL bundle sourcemap(s) in console output
configuration.preprocessors[conf.path.dll('**/*.bundle.js')] = ['sourcemap'];
if (conf.typeScript) {
configuration.coverageReporter = { type: 'in-memory' };
configuration.remapCoverageReporter = {
'text-summary': null,
html: conf.path.coverage(),
* Copyright 2016-2018 Hippo B.V. (
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const autoprefixer = require('autoprefixer');
const clone = require('clone');
const webpack = require('webpack');
const { CheckerPlugin } = require('awesome-typescript-loader');
const conf = require('./build.conf');
const isProduction = process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== 'test';
const extensions = conf.typeScript ? ['.ts', '.js'] : ['.js'];
const scriptLoader = conf.typeScript ?
test: /\.+(js|ts)$/,
exclude: [/node_modules/, 'index.spec.*'],
use: [
loader: 'awesome-typescript-loader',
options: {
useBabel: true,
useCache: !isProduction,
usePrecompiledFiles: !isProduction,
useTranspileModule: !isProduction,
forceIsolatedModules: !isProduction,
transpileOnly: conf.cli.transpileOnly,
cacheDirectory: conf.path.cache('awcache'),
} : {
test: /\.js$/,
exclude: [/node_modules/, 'index.spec.*'],
use: 'babel-loader',
const baseConf = {
entry: {
app: conf.path.src('index'),
output: {
filename: '[name].js',
path: conf.paths.dist,
publicPath: conf.paths.publicPath,
resolve: {
module: {
rules: [
test: /.json$/,
use: 'json-loader',
exclude: /node_modules/,
test: [
exclude: [].concat(/node_modules/, conf.regexp.htmlExcludes),
use: 'raw-loader',
test: [
exclude: conf.regexp.htmlSvg,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[hash].[ext]',
test: [
exclude: /node_modules/,
use: [
loader: 'postcss-loader',
options: {
sourceMap: true,
plugins: [autoprefixer({ browsers: conf.browsers })],