Skip to content

Instantly share code, notes, and snippets.

@pnobbe
Created July 11, 2018 08:59
Show Gist options
  • Save pnobbe/41caf8a90be2b621a44aa3b69f10a78a to your computer and use it in GitHub Desktop.
Save pnobbe/41caf8a90be2b621a44aa3b69f10a78a to your computer and use it in GitHub Desktop.
/* eslint-disable no-console */
const path = require('path');
const flags = require('./webpack-flags');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const fs = require('fs');
const merge = require('webpack-merge');
const generic = require('./webpack.generic.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const BRANDING_PATH = path.resolve(`src/style/branding/${ flags.branding }`);
console.log('-- START BRAND BUNDLING --'.info);
/**
* BRANDING
* If a branding folder is specified, push a new path to the SASS pipeline that processes the branding SCSS.
*/
if (fs.existsSync(BRANDING_PATH)) { // Synchronously check if the path exists.
console.log('Branding'.info, `${ flags.branding }`.info.underline, 'found! Assets will be processed.'.info, `(${ BRANDING_PATH })`.dim.info);
} else {
console.error('Branding directory'.error, `${ BRANDING_PATH }`.error.underline, 'could not be found. Please check branding folders!'.error);
return;
}
module.exports = merge.smart(generic, {
/**
* ENTRY
* Declare all entry points for webpack
*/
entry: {
branding: `${ BRANDING_PATH }/branding.scss`
},
/**
* OUTPUT
* Declare output structure
* Contenthash is used in the output filename to allow for caching based on a content hash.
*/
output: {
filename: 'js/[name].js',
path: path.resolve(__dirname, 'dist/Web'),
sourceMapFilename: '[file].source.map'
},
module: {
rules: [
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
include: [/(node_modules)/, path.resolve(__dirname, 'src/style/fonts')],
use:
[
/**
* FILE-LOADER
* Instructs webpack to emit the required object as file and to return its public URL
*/
{
loader: 'file-loader',
options: {
name: (file) => {
if (file.includes('branding')) {
return '[name].[ext]';
}
return '[name].[hash].[ext]';
},
outputPath: 'fonts/'
}
}
]
},
{
test: /\.(gif|png|jpe?g|svg)(\?.*)?$/,
exclude: [/(node_modules)/, path.resolve(__dirname, 'src/style/fonts')],
use:
[
/**
* FILE-LOADER
* Instructs webpack to emit the required object as file and to return its public URL
*/
{
loader: 'file-loader',
options: {
name: (file) => {
if (file.includes('branding')) {
return '[name].[ext]';
}
return '[name].[hash].[ext]';
},
outputPath: 'images/'
}
},
/**
* IMAGE-LOADER
* Optimizes images for web use.
*/
{
loader: 'image-webpack-loader',
options: {
disable: true // Disable image processing when in debug mode
}
}
]
}
]
},
/**
* PLUGINS
* Use plugins to add functionality typically related to bundles in webpack.
*/
plugins: [
/**
* MINI CSS EXTRACT PLUGIN
* This plugin extracts CSS into separate files.
* It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
*/
new MiniCssExtractPlugin({
filename: 'style/[name].css',
chunkFilename: 'style/[name].css',
allChunks: true
}),
/**
* COPY WEBPACK PLUGIN
* Copies individual files or entire directories to the build directory.
*/
new CopyWebpackPlugin([
{
// Copy any existing branding json files to dist/Web/settings folder and overwrite defaults.
from: `${ BRANDING_PATH }/*.json`,
to: 'settings/',
force: true,
flatten: true
},
{
// Copy any existing branding xml files to dist/Web/settings folder and overwrite defaults.
from: `${ BRANDING_PATH }/*.xml`,
to: '../',
force: true,
flatten: true
},
{
// Copy any existing favicons to dist/Web/images/favicons/ folder and overwrite defaults.
from: `${ BRANDING_PATH }/*.png`,
to: 'images/favicons',
force: true,
flatten: true
}
])
]
});
/* eslint-disable no-console */
const path = require('path');
const merge = require('webpack-merge');
const generic = require('./webpack.generic.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const fs = require('fs');
const ec = require('./environment-config.js');
const flags = require('./webpack-flags');
console.log('-- START CORE BUNDLING --'.info);
const buildInfo = {
buildDate: new Date().toISOString()
};
console.log('Generating build info…'.verbose);
fs.writeFileSync('./src/js/build-info.json', JSON.stringify(buildInfo));
console.log('Generating environment configuration…'.verbose);
fs.writeFileSync('./src/js/environment.json', JSON.stringify(flags.test ? ec.productionTest : ec.production));
module.exports = merge.smart(generic, {
/**
* ENTRY
* Declare all entry points for webpack
*/
entry: {
core: [
'babel-polyfill',
'./src/index.js',
'./src/style/ss-base.scss'
]
},
/**
* OUTPUT
* Declare output structure
* Contenthash is used in the output filename to allow for caching based on a content hash.
*/
output: {
filename: 'js/[name].[contenthash].js',
chunkFilename: 'js/[name].[contenthash].js',
path: path.resolve(__dirname, 'dist/Web'),
sourceMapFilename: '[file].source.map'
},
/**
* NODE
* Mock Node.js globals & modules
*/
node: {
console: true,
fs: 'empty'
},
/**
* OPTIMIZATION
* Setting optimization.runtimeChunk to 'single' creates a runtime file to be shared for all generated chunks.
* optimization.splitChunks is used to avoid duplicated dependencies across chunks and define a separate vendor chunk to bundle node_modules.
*/
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
module: {
rules: [
{
test: /\.scss$/,
exclude: [/(node_modules)/],
use: [
/**
* MINI CSS EXTRACT PLUGIN
* Extracts CSS into separate files.
* It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
*/
{
loader: MiniCssExtractPlugin.loader,
options: { publicPath: '/' }
},
/**
* CSS-LOADER
* Translates CSS into CommonJS
* The css-loader interprets @import and url() like import/require() and will resolve them.
*/
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
/**
* POSTCSS-LOADER
* Add vendor prefixes to CSS rules using values from Can I Use.
* Autoprefixer will use the data based on current browser popularity and property support to apply prefixes for you.
*/
{
loader: 'postcss-loader',
options: {
autoprefixer: {
browsers: ['last 2 versions']
},
plugins: () => [
autoprefixer
],
sourceMap: true
}
},
/**
* SASS-LOADER
* Loads a Sass/SCSS file and compiles it to CSS.
* Use the css-loader or the raw-loader to turn it into a JS module and the MiniCssExtractPlugin to extract it into a separate file.
*/
{
loader: 'sass-loader',
options: {
sourceMap: true,
outFile: 'out', // for internal reference only: https://github.com/sass/node-sass
includePaths: [path.resolve('./src/js/components')]
}
}
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
include: [/(node_modules)/, path.resolve(__dirname, 'src/style/fonts')],
use:
[
/**
* FILE-LOADER
* Instructs webpack to emit the required object as file and to return its public URL
*/
{
loader: 'file-loader',
options: {
name: (file) => {
if (file.includes('branding')) {
return '[name].[ext]';
}
return '[name].[hash].[ext]';
},
outputPath: 'fonts/'
}
}
]
},
{
test: /\.(gif|png|jpe?g|svg)(\?.*)?$/,
exclude: [/(node_modules)/, path.resolve(__dirname, 'src/style/fonts')],
use:
[
/**
* FILE-LOADER
* Instructs webpack to emit the required object as file and to return its public URL
*/
{
loader: 'file-loader',
options: {
name: (file) => {
if (file.includes('branding')) {
return '[name].[ext]';
}
return '[name].[hash].[ext]';
},
outputPath: 'images/'
}
},
/**
* IMAGE-LOADER
* Optimizes images for web use.
*/
{
loader: 'image-webpack-loader',
options: {
disable: true // Disable image processing when in debug mode
}
}
]
}
]
},
plugins: [
/**
* MINI CSS EXTRACT PLUGIN
* This plugin extracts CSS into separate files.
* It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
*/
new MiniCssExtractPlugin({
filename: 'style/[name].[contenthash].css',
chunkFilename: 'style/[name].[contenthash].css',
allChunks: true
}),
/**
* COPY WEBPACK PLUGIN
* Copies individual files or entire directories to the build directory.
*/
new CopyWebpackPlugin([
{
// Copy default json files to dist/Web/settings folder.
from: 'xml/*.json',
to: 'settings/',
flatten: true
},
{
// Copy default xml files to dist/Web folder.
from: 'xml/*.xml',
to: '../',
flatten: true
},
{
// Copy any existing favicons to dist/Web/images/favicons/ folder and overwrite defaults.
from: 'src/style/branding/se/*.png',
to: 'images/favicons',
force: true,
flatten: true
}
]),
/**
* HTML WEBPACK PLUGIN
* This is a webpack plugin that simplifies creation of HTML files to serve your webpack bundles.
* This is especially useful for webpack bundles that include a hash in the filename which changes every compilation.
* You can either let the plugin generate an HTML file for you, supply your own template using lodash templates or use your own loader.
*/
new HtmlWebpackPlugin({
title: 'Production',
template: 'src/html/index.html'
})
]
});
/* eslint-disable no-console */
/**
* DEVELOPMENT CONFIGURATION
**/
const backendList = require('./backendList');
const merge = require('webpack-merge');
const core = require('./webpack.core');
const branding = require('./webpack.branding');
const backendMockServer = require('./backendMockServer');
const environment = require('./environment-config').development;
const fs = require('fs');
const flags = require('./webpack-flags');
const pem = require('pem');
module.exports = new Promise((resolve, reject) => {
console.log('Generating environment configuration…'.verbose);
fs.writeFileSync('./src/js/environment', JSON.stringify(environment));
const MOCK_URL = `https://localhost:${ flags.mockPort }`;
const LIVE_URL = backendList[flags.backend];
console.log('Backend: ', flags.backend);
console.log('Live URL: ', LIVE_URL);
// Start mock server for google tile
backendMockServer.listen(flags.mockPort, () => {
console.log(`Backend mock server running on port: ${ flags.mockPort }`.info);
});
if (flags.mock) {
console.log('Running against MOCK server'.info);
} else {
console.log('Running against LIVE server'.info);
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // Disables Node's rejection of invalid/unauthorized certificates
}
const mockConfig = {
target: MOCK_URL,
secure: false
};
const liveConfig = {
target: LIVE_URL,
secure: false
};
const config = flags.mock ? mockConfig : liveConfig;
const proxyConfig = {
'/auth/lite': flags.mock ? config : Object.assign(config, {
onProxyRes(proxyRes) {
const cookies = proxyRes.headers['set-cookie'];
if (cookies && cookies.length) {
proxyRes.headers['set-cookie'] = cookies.map((c) => {
return c.replace(/domain=[^;]*;/, '');
});
}
}
}),
'/auth/logout': config,
'/api/**': config,
'/tiles/**': config,
'/google/tile/**': mockConfig, // use mock config regardless for Google endpoints
'/google/createSession': Object.assign(mockConfig, {
pathRewrite: (path, req) => {
return `/tile/v1/createSession?key=${ req.query.key }`;
}
}),
'/google/viewport': Object.assign(mockConfig, {
pathRewrite: (path, req) => {
const {
key, session, zoom, north, south, east, west
} = req.query;
return `google/tile/v1/viewport?key=${ key }&session=${ session }&zoom=${ zoom }&north=${ north }&south=${ south }&east=${ east }&west=${ west }`;
}
})
};
console.log('Generating SSL certificates…'.verbose);
pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
if (err) {
reject(err);
}
console.log('Finished generating SSL certificates!'.verbose);
process.env.NODE_EXTRA_CA_CERTS = './path/to/root-cas.pem';
resolve(merge.smart([core, branding, {
mode: 'development', // Set mode to development
devtool: 'inline-source-map', // Use inline source mapping for more
devServer: {
open: flags.open,
host: '0.0.0.0',
port: flags.port,
public: `localhost:${ flags.port }`,
contentBase: './dist/Web',
historyApiFallback: true,
inline: false,
quiet: false,
//noInfo: true,
compress: true,
clientLogLevel: 'info',
https: {
key: keys.serviceKey,
cert: keys.certificate
},
overlay: {
errors: true
},
disableHostCheck: true,
stats: 'errors-only',
proxy: proxyConfig
}
}]));
});
});
/* eslint-disable no-console */
const path = require('path');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const colors = require('colors');
const autoprefixer = require('autoprefixer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
colors.setTheme({
silly: 'rainbow',
input: 'grey',
verbose: 'cyan',
prompt: 'grey',
info: 'green',
data: 'grey',
help: 'cyan',
warn: 'yellow',
debug: 'blue',
error: 'red'
});
module.exports = {
/**
* RESOLVE
* Configure how modules are resolved
*/
resolve: {
extensions: ['.js', '.jsx', 'json'],
modules: [
'src',
'node_modules'
],
aliasFields: ['browser'],
/**
* ALIAS
* Create aliases to import or require certain modules more easily.
* For example, to alias a bunch of commonly used src/ folders:
*/
alias: {
webworkify: 'webworkify-webpack',
Resources: path.resolve(__dirname, 'src/js/store/resources/'),
Services: path.resolve(__dirname, 'src/js/store/services/'),
Reducers: path.resolve(__dirname, 'src/js/store/reducers/'),
Components: path.resolve(__dirname, 'src/js/components/'),
PropertyComponents: path.resolve(__dirname, 'src/js/components/properties'),
Store: path.resolve(__dirname, 'src/js/store/'),
Utilities: path.resolve(__dirname, 'src/js/utilities/'),
Utils: path.resolve(__dirname, 'src/js/utilities'),
Bus: path.resolve(__dirname, 'src/js/bus/'),
Types: path.resolve(__dirname, 'src/js/store/types'),
JSRoot: path.resolve(__dirname, 'src/js'),
Constants: path.resolve(__dirname, 'src/js/constants'),
CONSTANTS: path.resolve(__dirname, 'src/js/constants/index.js')
}
},
module: {
rules: [
{
test: /\.(js|jsx)?$/,
include: path.join(__dirname, 'src'),
exclude: [/(node_modules)/],
use: [
/**
* BABEL-LOADER
* This package allows transpiling JavaScript files using Babel.
*/
{
loader: 'babel-loader',
options: {
presets: ['es2015', 'stage-0', 'react'],
plugins: [
'add-module-exports',
'transform-decorators-legacy'
],
cacheDirectory: '_babel_cache'
}
}
]
},
{
test: /\.scss$/,
exclude: [/(node_modules)/],
use: [
/**
* MINI CSS EXTRACT PLUGIN
* Extracts CSS into separate files.
* It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
*/
{
loader: MiniCssExtractPlugin.loader,
options: { publicPath: '/' }
},
/**
* CSS-LOADER
* Translates CSS into CommonJS
* The css-loader interprets @import and url() like import/require() and will resolve them.
*/
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
/**
* POSTCSS-LOADER
* Add vendor prefixes to CSS rules using values from Can I Use.
* Autoprefixer will use the data based on current browser popularity and property support to apply prefixes for you.
*/
{
loader: 'postcss-loader',
options: {
autoprefixer: {
browsers: ['last 2 versions']
},
plugins: () => [
autoprefixer
],
sourceMap: true
}
},
/**
* SASS-LOADER
* Loads a Sass/SCSS file and compiles it to CSS.
* Use the css-loader or the raw-loader to turn it into a JS module and the MiniCssExtractPlugin to extract it into a separate file.
*/
{
loader: 'sass-loader',
options: {
sourceMap: true,
outFile: 'out', // for internal reference only: https://github.com/sass/node-sass
includePaths: [path.resolve('./src/js/components')]
}
}
]
}
]
},
/**
* PLUGINS
* Use plugins to add functionality typically related to bundles in webpack.
*/
plugins: [
/**
* PROGRESSBAR PLUGIN
* Adds a progress bar to the CLI build process.
*/
new ProgressBarPlugin()
]
};
/* eslint-disable no-console */
/* eslint-disable global-require */
/**
* PRODUCTION CONFIGURATION
**/
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const flags = require('./webpack-flags');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const config = {
mode: 'production', // Set mode to production
devtool: 'source-map', // Use quickest source mapping for production to encourage debugging and benchmarking while keeping bundles small
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production') // Specify the production environment for Node as many libraries determine logging behaviour off of this.
}),
new UglifyJSPlugin({
cache: true,
parallel: true,
sourceMap: true // Allow UglifyJS to remove dead code using source maps
}),
new OptimizeCSSAssetsPlugin(), // Minify CSS -- don't use css loader because this is faster & more flexible,
/**
* CLEAN WEBPACK PLUGIN
* A webpack plugin to remove your build folder(s) before building
*/
new CleanWebpackPlugin('dist')
]
};
if (flags.analyze) {
console.log('Analyze'.info.underline + ' flag enabled, bundle will be analyzed.'.info);
config.plugins.push(new BundleAnalyzerPlugin());
}
module.exports = () => {
if (flags.only !== undefined) {
switch (flags.only) {
case 'branding':
case 'brand':
return merge(require('./webpack.branding'), config);
case 'core':
return merge(require('./webpack.core'), config);
default:
throw new Error('Invalid config');
}
}
return merge(require('./webpack.core'), require('./webpack.branding'), config);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment