Files
frontend-app-profile/webpack/webpack.prod.config.js
David Joy 8f37cc1a8d Organize the repo and export profile module properly (#262)
* Moving files to their new homes.

Subsequent commit will wire everything up again.

* Relink files and split stylesheet.

Requires adding resolve-url-loader to fix sass import relativity.

* Remove browserslist warning.

* Remove the need for ProfileMain

* Fix test issues - needed thunk.
2019-09-23 13:50:56 -04:00

223 lines
7.9 KiB
JavaScript
Executable File

// This is the prod Webpack config. All settings here should prefer smaller,
// optimized bundles at the expense of a longer build time.
const Merge = require('webpack-merge');
const commonConfig = require('./webpack.common.config.js');
const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackNewRelicPlugin = require('html-webpack-new-relic-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PurgecssPlugin = require('purgecss-webpack-plugin');
const NewRelicSourceMapPlugin = require('new-relic-source-map-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // eslint-disable-line prefer-destructuring
const PostCssRtlPlugin = require('postcss-rtl');
const PostCssAutoprefixerPlugin = require('autoprefixer');
const CssNano = require('cssnano');
module.exports = Merge.smart(commonConfig, {
mode: 'production',
devtool: 'source-map',
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, '../dist'),
},
module: {
// Specify file-by-file rules to Webpack. Some file-types need a particular kind of loader.
rules: [
// The babel-loader transforms newer ES2015+ syntax to older ES5 for older browsers.
// Babel is configured with the .babelrc file at the root of the project.
{
test: /\.(js|jsx)$/,
include: [
path.resolve(__dirname, '../src'),
path.resolve(__dirname, '../footer'),
path.resolve(__dirname, '../header'),
],
loader: 'babel-loader',
},
{
test: /\.js$/,
use: ['source-map-loader'],
enforce: 'pre',
},
// Webpack, by default, includes all CSS in the javascript bundles. Unfortunately, that means:
// a) The CSS won't be cached by browsers separately (a javascript change will force CSS
// re-download). b) Since CSS is applied asyncronously, it causes an ugly
// flash-of-unstyled-content.
//
// To avoid these problems, we extract the CSS from the bundles into separate CSS files that
// can be included as <link> tags in the HTML <head> manually.
//
// We will not do this in development because it prevents hot-reloading from working and it
// increases build time.
{
test: /(.scss|.css)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader', // translates CSS into CommonJS
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
plugins: () => [
PostCssRtlPlugin(),
PostCssAutoprefixerPlugin({ grid: true }),
CssNano(),
],
},
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
sourceMap: true,
includePaths: [
path.join(__dirname, '../node_modules'),
path.join(__dirname, '../src'),
],
},
},
],
},
{
test: /.svg$/,
issuer: {
test: /\.jsx?$/,
},
loader: '@svgr/webpack',
},
// Webpack, by default, uses the url-loader for images and fonts that are required/included by
// files it processes, which just base64 encodes them and inlines them in the javascript
// bundles. This makes the javascript bundles ginormous and defeats caching so we will use the
// file-loader instead to copy the files directly to the output directory.
{
test: /\.(woff2?|ttf|svg|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
},
{
test: /\.(jpe?g|png|gif|ico)(\?v=\d+\.\d+\.\d+)?$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
optimizationlevel: 7,
mozjpeg: {
progressive: true,
},
gifsicle: {
interlaced: false,
},
pngquant: {
quality: '65-90',
speed: 4,
},
},
},
],
},
],
},
// New in Webpack 4. Replaces CommonChunksPlugin. Extract common modules among all chunks to one
// common chunk and extract the Webpack runtime to a single runtime chunk.
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
},
},
// Specify additional processing or side-effects done on the Webpack output bundles as a whole.
plugins: [
// Cleans the dist directory before each build
new CleanWebpackPlugin(['dist'], {
root: path.join(__dirname, '../'),
}),
// Writes the extracted CSS from each entry to a file in the output directory.
new MiniCssExtractPlugin({
filename: '[name].[chunkhash].css',
}),
// Scan files for class names and ids and remove unused css
new PurgecssPlugin({
paths: [].concat(
// Scan files in this app
glob.sync(`${path.resolve(__dirname, '../src')}/**/*`, { nodir: true }),
// Scan files in any edx frontend-component
glob.sync(`${path.resolve(__dirname, '../node_modules/@edx/frontend-component')}*/**/*`, { nodir: true }),
// Scan files in paragon
glob.sync(`${path.resolve(__dirname, '../node_modules/@edx/paragon')}/**/*`, { nodir: true }),
),
// Protect react-css-transition class names
whitelistPatterns: [/-enter/, /-appear/, /-exit/],
}),
// Generates an HTML file in the output directory.
new HtmlWebpackPlugin({
inject: true, // Appends script tags linking to the webpack bundles at the end of the body
template: path.resolve(__dirname, '../public/index.html'),
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
// App configuration
ACCESS_TOKEN_COOKIE_NAME: null,
BASE_URL: null,
CREDENTIALS_BASE_URL: null,
CSRF_COOKIE_NAME: 'csrftoken',
CSRF_TOKEN_API_PATH: null,
ECOMMERCE_BASE_URL: null,
LANGUAGE_PREFERENCE_COOKIE_NAME: null,
LMS_BASE_URL: null,
LOGIN_URL: null,
LOGOUT_URL: null,
MARKETING_SITE_BASE_URL: null,
ORDER_HISTORY_URL: null,
REFRESH_ACCESS_TOKEN_ENDPOINT: null,
SEGMENT_KEY: null,
SITE_NAME: null,
USER_INFO_COOKIE_NAME: null,
// ProfileFooter configuration
APPLE_APP_STORE_URL: null,
CONTACT_URL: null,
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM: null,
ENTERPRISE_MARKETING_URL: null,
ENTERPRISE_MARKETING_UTM_CAMPAIGN: null,
ENTERPRISE_MARKETING_UTM_SOURCE: null,
FACEBOOK_URL: null,
GOOGLE_PLAY_URL: null,
LINKED_IN_URL: null,
OPEN_SOURCE_URL: null,
PRIVACY_POLICY_URL: null,
REDDIT_URL: null,
SUPPORT_URL: null,
TERMS_OF_SERVICE_URL: null,
TWITTER_URL: null,
YOU_TUBE_URL: null,
}),
new HtmlWebpackNewRelicPlugin({
// This plugin fixes an issue where the newrelic script will break if
// not added directly to the HTML.
// We use non empty strings as defaults here to prevent errors for empty configs
license: process.env.NEW_RELIC_LICENSE_KEY || 'fake_app',
applicationID: process.env.NEW_RELIC_APP_ID || 'fake_license',
}),
new NewRelicSourceMapPlugin({
applicationId: process.env.NEW_RELIC_APP_ID,
nrAdminKey: process.env.NEW_RELIC_ADMIN_KEY,
staticAssetUrl: process.env.BASE_URL,
noop: typeof process.env.NEW_RELIC_ADMIN_KEY === 'undefined', // upload source maps in prod builds only
}),
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
}),
],
});