Skip to content

Instantly share code, notes, and snippets.

@praveenperera
Created March 20, 2018 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save praveenperera/f048f21eef1daef98a4c8f6cb834d2af to your computer and use it in GitHub Desktop.
Save praveenperera/f048f21eef1daef98a4c8f6cb834d2af to your computer and use it in GitHub Desktop.
"use strict";
const autoprefixer = require("autoprefixer");
const SWPrecacheWebpackPlugin = require("sw-precache-webpack-plugin");
const DefinePlugin = require("webpack/lib/DefinePlugin");
const UglifyJsPlugin = require("webpack/lib/optimize/UglifyJsPlugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const AssetsPlugin = require("assets-webpack-plugin");
const InterpolateHtmlPlugin = require("react-dev-utils/InterpolateHtmlPlugin");
const getClientEnvironment = require("./env");
const tailwindcss = require("tailwindcss");
const paths = require("../config/paths");
// Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
const publicPath = process.env.PUBLIC_URL;
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
const shouldUseRelativeAssetPaths = publicPath === "./";
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
const publicUrl = publicPath.slice(0, -1);
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// Note: defined here because it will be used more than once.
const cssFilename = "static/css/[name].[contenthash:8].css";
// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// To have this structure working with relative paths, we have to use custom options.
const extractTextPluginOptions = shouldUseRelativeAssetPaths
? // Making sure that the publicPath goes back to to build folder.
{ publicPath: Array(cssFilename.split("/").length).join("../") }
: {};
const PurgecssPlugin = require("purgecss-webpack-plugin");
//https://tailwindcss.com/docs/controlling-file-size
// https://github.com/FullHuman/purgecss#extractor
class TailwindExtractor {
static extract(content) {
return content.match(/[A-z0-9-:\/]+/g) || [];
}
}
module.exports = {
bail: true,
entry: [paths.appIndexJs],
output: {
// The build folder.
path: paths.appBuild,
// Append leading slash when production assets are referenced in the html.
publicPath: publicPath,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// Generated JS files.
filename: "static/js/[name].[chunkhash:8].js",
},
resolve: {
modules: ["node_modules"],
extensions: [".js", ".elm"],
},
module: {
noParse: /\.elm$/,
rules: [
{
test: /\.jsx?$/,
exclude: [/elm-stuff/, /node_modules/],
loader: require.resolve("babel-loader"),
},
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: [
{
loader: require.resolve("string-replace-loader"),
query: {
multiple: [
{
search: "%PUBLIC_URL%",
replace: publicUrl,
},
{
search: "%API_URL%",
replace: process.env.API_URL,
},
],
},
},
{
// Use the local installation of elm-make
loader: require.resolve("elm-webpack-loader"),
options: {
debug: process.env.ELM_DEBUGGER === "true" ? true : false,
pathToMake: paths.elmMake,
},
},
],
},
{
test: /\.css$/,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve("postcss-loader"),
options: {
ident: "postcss", // https://webpack.js.org/guides/migrating/#complex-options
plugins: () => [
autoprefixer({
browsers: [
">1%",
"last 4 versions",
"Firefox ESR",
"not ie < 9",
],
}),
],
},
},
],
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract(
Object.assign(
{
fallback: "style-loader",
use: [
{
loader: "css-loader",
options: {
includePaths: [paths.node_modules],
sourceMap: true,
},
},
{
loader: "postcss-loader",
options: {
ident: "postcss", // https://webpack.js.org/guides/migrating/#complex-options
sourceMap: true,
plugins: () => [
autoprefixer({
browsers: [
">1%",
"last 4 versions",
"Firefox ESR",
"not ie < 9",
],
}),
tailwindcss("./config/tailwind.js"),
],
},
},
{
loader: "sass-loader",
options: {
includePaths: [paths.node_modules],
sourceMap: true,
},
},
],
},
extractTextPluginOptions
)
),
},
{
exclude: [
/\.html$/,
/\.js$/,
/\.elm$/,
/\.css$/,
/\.scss$/,
/\.json$/,
/\.svg$/,
],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]",
},
},
// "file" loader for svg
{
test: /\.svg$/,
loader: require.resolve("file-loader"),
options: {
name: "static/media/[name].[hash:8].[ext]",
},
},
],
},
plugins: [
new AssetsPlugin({ path: paths.appBuild }),
new DefinePlugin(env.stringified),
new InterpolateHtmlPlugin(env.raw),
/* Minify the compiled JavaScript. */
/* new UglifyJsPlugin({
* compress: {
* warnings: false,
* dead_code: true,
* pure_funcs: [
* "_elm_lang$core$Native_Utils.update",
* "A2",
* "A3",
* "A4",
* "A5",
* "A6",
* "A7",
* "A8",
* "A9",
* "F2",
* "F3",
* "F4",
* "F5",
* "F6",
* "F7",
* "F8",
* "F9",
* ],
* },
* output: {
* comments: false,
* },
* }), */
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
new ExtractTextPlugin({
filename: cssFilename,
}),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the Webpack build.
new SWPrecacheWebpackPlugin({
// By default, a cache-busting query parameter is appended to requests
// used to populate the caches, to ensure the responses are fresh.
// If a URL is already hashed by Webpack, then there is no concern
// about it being stale, and the cache-busting can be skipped.
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: "service-worker.js",
logger(message) {
if (message.indexOf("Total precache size is") === 0) {
// This message occurs for every build and is a bit too noisy.
return;
}
if (message.indexOf("Skipping static resource") === 0) {
// This message obscures real errors so we ignore it.
// https://github.com/facebookincubator/create-react-app/issues/2612
return;
}
console.log(message);
},
minify: true,
// For unknown URLs, fallback to the index page
navigateFallback: publicUrl + "/index.html",
// Ignores URLs starting from /__ (useful for Firebase):
// https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219
navigateFallbackWhitelist: [/^(?!\/__).*/],
// Don't precache sourcemaps (they're large) and build asset manifest:
staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
}),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty",
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment