tix-react-ssr
Version:
Tiket.com React Project Scripts
401 lines (356 loc) • 11 kB
JavaScript
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const workboxPlugin = require('workbox-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const multi = require('multi-loader');
const paths = require('../config/paths');
const config = require('config').util.loadFileConfigs(paths.appPath + '/config');
const pkg = require('../package.json');
const progressHandler = require('./progress');
const { argv, env : { NODE_ENV, SOURCE_MAP, DEV_SERVER, ALLOW_CONSOLE } } = process;
const isDevEnv = NODE_ENV !== 'production';
const isDevServer = !!DEV_SERVER;
const useSourceMap = SOURCE_MAP !== 'false';
const isVerbose = argv.includes('--verbose');
const isAnalyze = argv.includes('--analyze') || argv.includes('--analyse');
console.log('Building webpack isDevServer: ' + isDevServer + ', isDevEnv: ' + isDevEnv + ', useSourceMap: ' + useSourceMap);
//
// Common configuration chunk to be used for both
// client-side (client.js) and server-side (server.js) bundles
// -----------------------------------------------------------------------------
const webpackConfig = ({ isClient }) => ({
output: {
path: paths.appBuild + '/public/assets/',
publicPath: config.compiler_public_path || '/assets/',
pathinfo: isVerbose
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
build: paths.appBuild
}
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: (modulePath)=>{
return /node_modules/.test(modulePath) &&
!/node_modules|@tiketdotcom/.test(modulePath);
},
use: [
{
loader: 'babel-loader',
options: {
babelrc: false,
presets: [
[
'env',
{
targets: {
...(!isClient
? { node: pkg.engines.node.match(/(\d+\.?)+/)[0] }
: { browsers: pkg.browserslist }),
},
modules: false,
useBuiltIns: true,
},
],
'stage-0',
'react',
...(isDevServer ? [] : ['react-optimize']),
],
plugins: [
'lodash',
'transform-regenerator',
'transform-decorators-legacy'
],
},
},
],
},
{
test: /\.(graphql|gql)$/,
use: ['graphql-tag/loader'],
},
{
test: /\.(eot|ttf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
emitFile: isClient,
},
},
],
},
{
test: /\.(png|jpe?g)$/i,
use: multi(
`file-loader?name=${isDevServer ? '[name].[ext]' : '[name].[ext]'}.webp!webp-loader?{quality: 95}`,
`file-loader?name=${isDevServer ? '[name].[ext]' : '[name].[ext]'}`
),
},
{
test: /\.(gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
limit: 1024,
name: isDevServer ? '[name].[ext]' : '[hash:8].[ext]',
emitFile: isClient,
},
},
],
},
// Exclude dev modules from production build
...isDevServer ? [] : [
{
test: path.resolve(__dirname, '../node_modules/react-deep-force-update/lib/index.js'),
use: 'null-loader',
},
],
],
},
plugins: [
new webpack.ProgressPlugin({ handler: progressHandler }),
new StyleLintPlugin({
configFile: paths.appPath + '/.stylelintrc',
syntax: 'scss'
})
],
// Don't attempt to continue if there are any errors.
bail: !isDevEnv,
cache: isDevEnv,
stats: 'minimal'
});
const styleLoaders = ({ isClient }) => [
{
loader: `css-loader${isClient ? '' : '/locals'}`,
options: {
minimize: !isDevEnv,
module: false,
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
config: {
path: path.resolve(__dirname, './postcss.config.js')
}
},
},
{
loader: 'sass-loader'
},
];
//
// Configuration for the client-side bundle (client.js)
// -----------------------------------------------------------------------------
const baseClientConfig = webpackConfig({ isClient: true });
const clientConfig = {
...baseClientConfig,
name: 'client',
target: 'web',
performance: {
hints: !isDevEnv ? 'warning' : false,
assetFilter: assetFilename => !/\.map|server.js$/.test(assetFilename),
},
entry: {
client: [
'babel-polyfill',
path.resolve(__dirname, './polyfills.js'),
paths.appSrc + '/client.js',
]
},
output: {
...baseClientConfig.output,
filename: isDevServer ? '[name].js' : '[name].[chunkhash:8].js',
chunkFilename: isDevServer ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js',
crossOriginLoading: 'anonymous',
libraryTarget: 'umd',
},
module: {
rules: [
...baseClientConfig.module.rules,
{
test: /\.s?css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: styleLoaders({ isClient: true }),
allChunks: true
}),
}
]
},
plugins: [
...baseClientConfig.plugins,
// Define free variables
// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
new webpack.DefinePlugin({
CONFIG: JSON.stringify(config.globals),
'process.env.DEV_SERVER': isDevServer,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.BROWSER': true,
__DEVTOOLS__: isVerbose // <-------- DISABLE redux-devtools HERE
}),
// Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk).
// http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => module.context && module.context.includes('node_modules'),
}),
new ExtractTextPlugin({
filename: isDevServer ? '[name].css' : '[name].[contenthash:8].css',
allChunks: true,
disable: isDevServer
}),
...(isDevServer ? [] : [
new webpack.optimize.ModuleConcatenationPlugin(),
// Minimize all JavaScript output of chunks
// https://github.com/mishoo/UglifyJS2#compressor-options
new webpack.optimize.UglifyJsPlugin({
sourceMap: useSourceMap,
compress: {
screw_ie8: true, // React doesn't support IE8
warnings: isVerbose,
unused: true,
dead_code: true,
drop_console: !ALLOW_CONSOLE
},
mangle: {
screw_ie8: true,
},
output: {
comments: false,
screw_ie8: true,
beautify: false
},
})
]),
// Emit a file with assets paths
// https://github.com/sporto/assets-webpack-plugin#options
new AssetsPlugin({
path: paths.appBuild,
filename: 'assets.json'
}),
// load `moment/locale/ja.js` and `moment/locale/it.js`
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /id|en-gb/),
// Webpack Bundle Analyzer
// https://github.com/th0r/webpack-bundle-analyzer
...isAnalyze ? [new BundleAnalyzerPlugin()] : [],
new workboxPlugin.GenerateSW({
cacheId: 'tiket-sw-cache-v1',
swDest: 'service-worker.js',
clientsClaim: true,
skipWaiting: true,
importWorkboxFrom: 'local',
ignoreUrlParametersMatching: [/./],
runtimeCaching: [
{
urlPattern: /^https:\/\/tixcore\.netlify\.com/,
handler: 'staleWhileRevalidate',
options: {
cacheName: 'core-libs'
}
},
{
urlPattern: /^https:\/\/[a-z0-9]+\.tiket\.com\/(assets_version|images)\//,
handler: 'cacheFirst',
options: {
cacheName: 'tiket'
}
}
]
})
],
// Choose a developer tool to enhance debugging
// http://webpack.github.io/docs/configuration.html#devtool
devtool: isDevEnv && useSourceMap ? 'cheap-module-source-map' : false,
// Some libraries const Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
// https://webpack.github.io/docs/configuration.html#node
// https://github.com/webpack/node-libs-browser/tree/master/mock
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
};
//
// Configuration for the server-side bundle (server.js)
// -----------------------------------------------------------------------------
const baseServerConfig = webpackConfig({ isClient: false });
const serverConfig = {
...baseServerConfig,
name: 'server',
target: 'node',
devtool: isDevEnv && useSourceMap ? 'source-map' : false,
performance: false,
entry: {
server: ['babel-polyfill', paths.appSrc + '/server.js'],
},
output: {
...baseServerConfig.output,
path: paths.appBuild,
filename: '[name].js',
libraryTarget: 'commonjs2',
},
module: {
...baseServerConfig.module,
// Override babel-preset-env configuration for Node.js
rules:[
...baseServerConfig.module.rules,
{
test: /\.s?css$/,
use: styleLoaders({ isClient: false }),
},
],
},
externals: [
/^\.\/assets\.json$/,
nodeExternals({ whitelist: /(@tiketdotcom|tix-react-ssr|\.(css|less|scss|sss)$)/i}),
],
plugins: [
...baseServerConfig.plugins,
new ExtractTextPlugin({
filename: 'styles.css',
allChunks: true,
disable: isDevServer
}),
// Define free variables
// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
new webpack.DefinePlugin({
CONFIG: JSON.stringify(config.globals),
'process.env.DEV_SERVER': isDevServer,
'process.env.BROWSER': false,
__DEVTOOLS__: isVerbose // <-------- DISABLE redux-devtools HERE
}),
// Do not create separate chunks of the server bundle
// https://webpack.github.io/docs/list-of-plugins.html#limitchunkcountplugin
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
new webpack.BannerPlugin({
banner: 'require("source-map-support").install();',
raw: true,
entryOnly: false,
})
],
node: {
console: false,
global: false,
process: false,
Buffer: false,
__filename: false,
__dirname: false,
}
};
const configs = [clientConfig, serverConfig];
module.exports = configs;