I'm having an issue with my webpack.prod.config building my assets properly or possibly an issue with my JS Babel configuration.
I can get it to work with the development build where it is inlining my CSS but it's not working when I try to pull it together into one CSS file for production. Whatever is happening it works in Dev with the CSS being injected directly by import './filename.css' in each of the respective components. It could also be the JS but either way when I build for prod the CSS is not working correctly neither is the JS. All the React JS components and other JS does not display, just the static HTML and CSS styling from the CDN imports. When I click on the URLs in the script tags injected by Webpack they just lead me to the same page instead of the JS or CSS source which I found odd. The JS and CSS looks to be correct in the Build > Static > JS + CSS outputs. Sometime I'm getting a received an text/html MIME when it was supposed to be something else message in the console.
Either that or my JS is broken and not building the page properly. Not in my production build (same build it does when it's deployed to Heroku). I started with a create-react-app (ejected), added Express, preCSS (for SASS like preprocessing), react-bootstrap and a few other things.
This project is sort of a mess as it's something I'm using as a learning tool for a new web dev to transition from using static HTML+CSS into using React, JS and Bootstrap (jQuery is in there temporarily as we convert things together into pure React). It was building previously without issue but since I started to mess with using postCSS + preCSS, but it's no longer working.
Here are some of the main packages/libraries I'm using. - jQuery (CDN Script Tag) - BS3 (CDN Script Tag, .js, .css) - React-Bootstrap - React-Overlays - Babel - postCSS - preCSS - ExtractTextPlugin
Thank you in advance for your help.
HTML + Error I'm getting in the console
[![HTML Being Generated][1]][1] [![Console Error][2]][2]
Webpack.config.prod.js
var path = require('path');
var precss = require('precss');
var autoprefixer = require('autoprefixer');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var url = require('url');
var paths = require('./paths');
var homepagePath = require(paths.appPackageJson).homepage;
var publicPath = homepagePath ? url.parse(homepagePath).pathname : '/';
if (!publicPath.endsWith('/')) {
// Prevents incorrect paths in file-loader
publicPath += '/';
}
module.exports = {
bail: true,
devtool: 'source-map',
entry: [
require.resolve('./polyfills'),
path.join(paths.appSrc, 'index')
],
output: {
path: paths.appBuild,
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
publicPath: publicPath
},
resolve: {
extensions: ['', '.js', '.json']
},
resolveLoader: {
root: paths.ownNodeModules,
moduleTemplates: ['*-loader']
},
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint',
include: paths.appSrc
}
],
loaders: [
{
test: /\.js$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.prod')
},
{
test: /\.css$/,
include: [paths.appSrc, paths.appNodeModules],
// Disable autoprefixer in css-loader itself:
// https://github.com/webpack/css-loader/issues/281
// We already have it thanks to postcss.
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss!sass')
},
{
test: /\.json$/,
include: [paths.appSrc, paths.appNodeModules],
loader: 'json'
},
{
test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/,
include: [paths.appSrc, paths.appNodeModules],
loader: 'file',
query: {
// name: 'static/media/[name].[hash:8].[ext]'
name: 'static/media/[name].[ext]'
}
},
{
test: /\.(mp4|webm)(\?.*)?$/,
include: [paths.appSrc, paths.appNodeModules],
loader: 'url',
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]
},
eslint: {
// TODO: consider separate config for production,
// e.g. to enable no-console and no-debugger only in prod.
configFile: path.join(__dirname, 'eslint.js'),
useEslintrc: false
},
postcss: function() {
return [precss, autoprefixer];
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
favicon: paths.appFavicon,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
warnings: false
},
mangle: {
screw_ie8: true
},
output: {
comments: false,
screw_ie8: true
}
}),
new ExtractTextPlugin('static/css/[name].[contenthash:8].css')
]
};
Build.js
process.env.NODE_ENV = 'production';
var chalk = require('chalk');
var fs = require('fs');
var path = require('path');
var filesize = require('filesize');
var gzipSize = require('gzip-size').sync;
var rimrafSync = require('rimraf').sync;
var webpack = require('webpack');
var config = require('../config/webpack.config.prod');
var paths = require('../config/paths');
var express = require('express');
var app = express();
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
rimrafSync(paths.appBuild + '/*');
console.log('Creating an optimized production build...');
webpack(config).run(function(err, stats) {
if (err) {
console.error('Failed to create a production build. Reason:');
console.error(err.message || err);
process.exit(1);
}
console.log(chalk.green('Compiled successfully.'));
console.log();
console.log('File sizes after gzip:');
console.log();
var assets = stats.toJson().assets
.filter(asset => /\.(js|css)$/.test(asset.name))
.map(asset => {
var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name);
var size = gzipSize(fileContents);
return {
folder: path.join('build', path.dirname(asset.name)),
name: path.basename(asset.name),
size: size,
sizeLabel: filesize(size)
};
});
assets.sort((a, b) => b.size - a.size);
var longestSizeLabelLength = Math.max.apply(null,
assets.map(a => a.sizeLabel.length)
);
assets.forEach(asset => {
var sizeLabel = asset.sizeLabel;
if (sizeLabel.length < longestSizeLabelLength) {
var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLabel.length);
sizeLabel += rightPadding;
}
console.log(
' ' + chalk.green(sizeLabel) +
' ' + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name)
);
});
console.log();
if (process.env.NODE_ENV === 'production') {
// Serve the static HTML file from paths.appBuild directory
app.use(express.static(paths.appBuild));
console.log('Static build directory now being served, paths.appBuild: ', paths.appBuild);
// Serve the static HTML file from express
console.log('Adding static path to Express routing...');
app.get('*', function(req, res) {
res.sendFile(paths.appHtml);
console.log('Path serving HTML at paths.appHTML: ', paths.appHtml);
});
// List out which port is being used and listen for changes on the server
app.listen(process.env.PORT || 9004, function(){
console.log('Express server listening on port %d in %s mode', (process.env.PORT || 9004), app.settings.env);
});
}
console.log();
});