eldewrito-menu/packages/frontend/webpack.config.babel.js

323 lines
8.9 KiB
JavaScript
Raw Normal View History

2018-04-24 10:13:48 +00:00
import {
DefinePlugin,
NamedModulesPlugin,
HashedModuleIdsPlugin,
LoaderOptionsPlugin,
HotModuleReplacementPlugin,
NoEmitOnErrorsPlugin,
optimize,
} from 'webpack';
import path from 'path';
import { isatty } from 'tty';
import chalk from 'chalk';
import _debug from 'debug';
// import slash from 'slash';
import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlPlugin from 'html-webpack-plugin';
import ProgressBarPlugin from 'progress-bar-webpack-plugin';
import UglifyJsPlugin from 'uglifyjs-webpack-plugin';
import Environment from '../../config/webpack/environment';
const debug = _debug('webpack:config');
debug.generated = _debug('webpack:config:generated');
debug.generated('filename:', __filename);
debug.generated('dirname:', __dirname);
const {
ModuleConcatenationPlugin,
} = optimize;
const websiteSubfolder = 'website';
export default (options) => {
const environment = new Environment({
ExtractTextPlugin, // @HACK
});
environment.input(options);
debug.generated(environment);
const {
development,
production,
server,
autoprefixerTargets,
} = environment;
const baseOutputFilename = development
? 'assets/dev/[name].dev.[ext]'
// Always use a hash (in production) to prevent files with the same name causing issues
: 'assets/prod/[chunkhash:2]/[name].[chunkhash:8].[ext]';
const webpackChunkFilename = baseOutputFilename
.replace(/\[ext(.*?)\]/g, 'js');
const webpackOutputFilename = webpackChunkFilename;
const assetOutputFilename = baseOutputFilename
.replace(/\[chunkhash(.*?)\]/g, '[hash$1]');
const cssOutputFileName = baseOutputFilename
.replace(/\[ext(.*?)\]/g, 'css');
// .replace(/\[chunkhash(.*?)\]/g, '[contenthash$1]');
2018-04-24 10:13:48 +00:00
// const cssOutputRebasePath = `${slash(path.relative(path.dirname(cssOutputFileName), ''))}/`;
const cssOutputRebasePath = '/';
// Default options for url-loader
const urlLoaderOptions = {
limit: 1, // Don't inline anything (but empty files) by default
name: assetOutputFilename,
publicPath: cssOutputRebasePath,
};
const config = {
name: 'frontend',
target: 'web',
devServer: {
// inline: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
// historyApiFallback: {
// index: '/',
// },
hot: true,
noInfo: true,
overlay: true,
publicPath: '',
quiet: false,
watchOptions: {
ignored: /node_modules/,
},
},
module: {
rules: [
{
test: /\.jsx?/i,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
// Look for babel configuration in project directory
babelrc: false,
// Cache transformations to the filesystem (in default temp dir)
cacheDirectory: true,
presets: [
['babel-preset-env', {
targets: {
browsers: autoprefixerTargets,
uglify: false,
},
// spec: true,
// debug: development,
modules: false, // do not transpile modules, webpack 2+ does that
}],
'babel-preset-react',
],
plugins: [
'babel-plugin-transform-react-constant-elements',
'babel-plugin-transform-class-properties',
'babel-plugin-transform-object-rest-spread',
['babel-plugin-transform-runtime', {
helpers: false,
polyfill: false,
regenerator: true,
}],
'babel-plugin-dynamic-import-webpack',
],
},
},
{
test: /\.json?/i,
loader: 'json-loader',
exclude: /node_modules/,
},
...[
/\.(gif|png|webp)$/i, // graphics
/\.svg$/i, // svg
/\.jpe?g$/i, // jpeg
/\.(mp4|ogg|webm)$/i, // video
/\.(eot|otf|ttf|woff|woff2)$/i, // fonts
/\.(wav|mp3|m4a|aac|oga)$/i, // audio
].map(test => ({
test,
loader: 'url-loader',
options: urlLoaderOptions,
})),
{
test: /\.css$/,
use: environment.styleLoaders(),
},
{
test: /\.s[ac]ss$/,
use: environment.styleLoaders(
{
loader: 'sass-loader',
},
),
},
{
test: /\.styl$/,
use: environment.styleLoaders(
{
loader: 'stylus-loader',
},
),
},
],
strictExportPresence: true,
},
output: {
filename: webpackOutputFilename,
chunkFilename: webpackChunkFilename,
path: path.join(__dirname, 'lib', websiteSubfolder),
publicPath: '',
},
plugins: [
// Show progress as a bar during build
isatty(1) && new ProgressBarPlugin({
complete: chalk.white('\u2588'),
incomplete: chalk.grey('\u2591'),
format: `:bar ${chalk.cyan.bold(':percent')} Webpack build: ${chalk.grey(':msg')}`,
}),
// Enforce case-sensitive import paths
new CaseSensitivePathsPlugin(),
// Replace specified expressions with values
new DefinePlugin({
'process.env.__DEV__': JSON.stringify(development),
'process.env.__PROD__': JSON.stringify(production),
'process.env.__SERVER__': JSON.stringify(server),
'process.env.NODE_ENV': JSON.stringify(production ? 'production' : 'development'),
}),
// Dev server build
...[
// Hot module reloading
new HotModuleReplacementPlugin(),
new NoEmitOnErrorsPlugin(),
// Use paths as names when serving
new NamedModulesPlugin(),
].filter(() => server),
// If we're not serving, we're creating a static build
...[// Extract imported stylesheets out into .css files
new ExtractTextPlugin({
allChunks: true,
filename: cssOutputFileName,
}),
].filter(() => !server),
// Move modules imported from node_modules/ into a vendor chunk when enabled
// FIXME - this plugin has been removed, use new option from Webpack 4
// new CommonsChunkPlugin({
// name: 'vendor',
// minChunks(module) {
// return (module.resource && module.resource.includes('node_modules'));
// },
// }),
// If we're generating an HTML file, we must be building a web app, so
// configure deterministic hashing for long-term caching.
// Generate stable module ids instead of having Webpack assign integers.
// NamedModulesPlugin allows for easier debugging and
// HashedModuleIdsPlugin does this without adding too much to bundle
// size.
development
? new NamedModulesPlugin()
: new HashedModuleIdsPlugin(),
// Production builds
...[
// JavaScript minification
new LoaderOptionsPlugin({ debug: false, minimize: true }),
// Hoisting
new ModuleConcatenationPlugin(),
].filter(() => production),
new HtmlPlugin({
template: path.join(__dirname, 'src', websiteSubfolder, 'index.html'),
filename: 'index.html',
hash: false,
inject: true,
compile: true,
favicon: false,
minify: production ? {
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
// includeAutoGeneratedTags: false,
collapseWhitespace: true,
// conservativeCollapse: true,
} : false,
cache: true,
showErrors: true,
chunks: 'all',
excludeChunks: [],
title: 'VIzon Countdown',
xhtml: false,
chunksSortMode: 'dependency',
}),
].filter(plugin => plugin !== false),
resolve: {
extensions: [
'.js', '.json', '.jsx',
],
alias: {
'moment-timezone': 'moment-timezone/builds/moment-timezone-with-data-2012-2022.js',
},
},
resolveLoader: {
modules: ['node_modules', 'nwb'],
},
optimization: {
minimize: production,
minimizer: [
new UglifyJsPlugin({
parallel: true,
uglifyOptions: {
compress: {
warnings: false,
},
output: {
comments: false,
},
},
sourceMap: true,
}),
],
},
devtool: server ? 'cheap-module-source-map' : 'source-map',
entry: {
app: [
...[
'eventsource-polyfill',
'react-hot-loader/patch',
'webpack-hot-middleware/client',
].filter(() => server).map(require.resolve),
path.join(__dirname, 'src', websiteSubfolder),
],
},
};
debug.generated(config);
return config;
};