tabs -> spaces

This commit is contained in:
Jason Miller
2018-03-29 15:43:14 -04:00
parent 5e6500d196
commit 76ceea0e52
19 changed files with 503 additions and 471 deletions

View File

@@ -3,27 +3,27 @@ let componentPath = require.resolve('./async-component');
module.exports = function () { };
module.exports.pitch = function (remainingRequest) {
this.cacheable && this.cacheable();
let query = loaderUtils.getOptions(this) || {};
let routeName = typeof query.name === 'function' ? query.name(this.resourcePath) : null;
let name;
if (routeName !== null) {
name = routeName;
}
else if ('name' in query) {
name = query.name;
}
else if ('formatName' in query) {
name = query.formatName(this.resourcePath);
}
this.cacheable && this.cacheable();
let query = loaderUtils.getOptions(this) || {};
let routeName = typeof query.name === 'function' ? query.name(this.resourcePath) : null;
let name;
if (routeName !== null) {
name = routeName;
}
else if ('name' in query) {
name = query.name;
}
else if ('formatName' in query) {
name = query.formatName(this.resourcePath);
}
return `
import async from ${JSON.stringify(componentPath)};
function load(cb) {
require.ensure([], function (require) {
cb( require(${loaderUtils.stringifyRequest(this, '!!' + remainingRequest)}) );
}${name ? (', ' + JSON.stringify(name)) : ''});
}
export default async(load);
`;
return `
import async from ${JSON.stringify(componentPath)};
function load(cb) {
require.ensure([], function (require) {
cb( require(${loaderUtils.stringifyRequest(this, '!!' + remainingRequest)}) );
}${name ? (', ' + JSON.stringify(name)) : ''});
}
export default async(load);
`;
};

View File

@@ -1,30 +1,30 @@
import { h, Component } from 'preact';
export default function (req) {
function Async() {
Component.call(this);
function Async() {
Component.call(this);
let b, old;
this.componentWillMount = () => {
b = this.base = this.nextBase || this.__b; // short circuits 1st render
req(m => {
this.setState({ child: m.default || m });
});
};
let b, old;
this.componentWillMount = () => {
b = this.base = this.nextBase || this.__b; // short circuits 1st render
req(m => {
this.setState({ child: m.default || m });
});
};
this.shouldComponentUpdate = (_, nxt) => {
nxt = nxt.child === void 0;
if (nxt && old === void 0 && !!b) {
old = h(b.nodeName, { dangerouslySetInnerHTML: { __html: b.innerHTML } });
}
else {
old = ''; // dump it
}
return !nxt;
};
this.shouldComponentUpdate = (_, nxt) => {
nxt = nxt.child === void 0;
if (nxt && old === void 0 && !!b) {
old = h(b.nodeName, { dangerouslySetInnerHTML: { __html: b.innerHTML } });
}
else {
old = ''; // dump it
}
return !nxt;
};
this.render = (p, s) => s.child ? h(s.child, p) : old;
}
(Async.prototype = new Component()).constructor = Async;
return Async;
this.render = (p, s) => s.child ? h(s.child, p) : old;
}
(Async.prototype = new Component()).constructor = Async;
return Async;
}

View File

@@ -1,27 +0,0 @@
import { h, render } from 'preact';
if (process.env.NODE_ENV === 'development') {
// enable preact devtools
require('preact/debug');
}
else if (process.env.ADD_SW && 'serviceWorker' in navigator && location.protocol === 'https:') {
// eslint-disable-next-line no-undef
navigator.serviceWorker.register(__webpack_public_path__ + 'sw.js');
}
const interopDefault = m => m && m.default ? m.default : m;
let app = interopDefault(require('app-entry-point'));
if (typeof app === 'function') {
let root = document.getElementById('app') || document.body.firstElementChild;
let init = () => {
let app = interopDefault(require('app-entry-point'));
root = render(h(app), document.body, root);
};
if (module.hot) module.hot.accept('app-entry-point', init);
init();
}

View File

@@ -0,0 +1,64 @@
const path = require('path');
const vm = require('vm');
module.exports = function (content) {
const jsdom = require('jsdom');
const preact = require('preact');
const renderToString = require('preact-render-to-string');
this.cacheable && this.cacheable();
const callback = this.async();
// const dom = new jsdom.JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`, {
const dom = new jsdom.JSDOM(content, {
includeNodeLocations: false,
runScripts: 'outside-only'
});
const { window } = dom;
const { document } = window;
// console.log(content);
const root = document.getElementById('app');
this.loadModule(path.join(__dirname, 'client-boot.js'), (err, source) => {
if (err) return callback(err);
console.log(source);
let mod = eval(source);
let props = {};
// console.log(mod);
let vnode = preact.createElement(mod, props);
let frag = document.createElement('div');
frag.innerHTML = renderToString(vnode);
root.parentNode.replaceChild(frag.firstChild, root);
let html = dom.serialize();
callback(null, html);
// return html = `module.exports = ${JSON.stringify(html)}`;
// return 'module.exports = ' + JSON.stringify(content).replace(/\{\{PRERENDER\}\}/gi, `" + require("preact-render-to-string")(require("app-entry-point")) + "`);
});
// global.window = global;
// global.document = {};
// return 'module.exports = ' + JSON.stringify(content).replace(/\{\{PRERENDER\}\}/gi, `" + require("preact-render-to-string")(require("app-entry-point")) + "`);
/*
let callback = this.async();
let parts = content.split(/\{\{prerender\}\}/gi);
if (parts.length<2) {
// callback(null, `module.exports = ${JSON.stringify(content)}`);
callback(null, content);
return;
}
// let html = `
// window = {};
// module.exports = ${JSON.stringify(parts[0])} + require("preact-render-to-string")(require("app-entry-point")) + ${JSON.stringify(parts[1])}`;
let html = `module.exports = ${JSON.stringify(parts[0])} + require("preact-render-to-string")(require("app-entry-point")) + ${JSON.stringify(parts[1])}`;
callback(null, html);
*/
};

View File

@@ -5,16 +5,16 @@ let renderToString = require('preact-render-to-string');
let appPath = path.join(__dirname, '../src/index');
module.exports = function(options) {
options = options || {};
let url = typeof options==='string' ? options : options.url;
global.history = {};
global.location = { href: url, pathname: url };
options = options || {};
let url = typeof options==='string' ? options : options.url;
global.history = {};
global.location = { href: url, pathname: url };
// let app = require('app-entry-point');
let app = require(appPath);
// let app = require('app-entry-point');
let app = require(appPath);
let html = renderToString(preact.h(app, { url }));
console.log(html);
let html = renderToString(preact.h(app, { url }));
console.log(html);
return html;
return html;
};

View File

@@ -8,23 +8,23 @@ const fs = require('fs');
* https://github.com/Jimdo/typings-for-css-modules-loader/issues/48#issuecomment-347036461
*/
module.exports = class WatchTimestampsPlugin {
constructor(patterns) {
this.patterns = patterns;
}
constructor(patterns) {
this.patterns = patterns;
}
apply(compiler) {
compiler.plugin('watch-run', (watch, callback) => {
const patterns = this.patterns;
const timestamps = watch.fileTimestamps;
apply(compiler) {
compiler.plugin('watch-run', (watch, callback) => {
const patterns = this.patterns;
const timestamps = watch.fileTimestamps;
for (const filepath of timestamps) {
if (patterns.some(pat => pat instanceof RegExp ? pat.test(filepath) : filepath.indexOf(pat) === 0)) {
let time = fs.statSync(filepath).mtime;
if (timestamps instanceof Map) timestamps.set(filepath, time);
else timestamps[filepath] = time;
}
}
callback();
});
}
for (const filepath of timestamps) {
if (patterns.some(pat => pat instanceof RegExp ? pat.test(filepath) : filepath.indexOf(pat) === 0)) {
let time = fs.statSync(filepath).mtime;
if (timestamps instanceof Map) timestamps.set(filepath, time);
else timestamps[filepath] = time;
}
}
callback();
});
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,21 +1,25 @@
@import '~style/helpers.scss';
.app {
position: absolute;
top: $toolbar-height;
left: 0;
width: 100%;
bottom: 0;
contain: size layout style;
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
display: flex;
flex-direction: column;
top: 0;
left: 0;
width: 100%;
bottom: 0;
overflow: hidden;
z-index: 1;
> .content {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: visible;
}
.header {
flex: 0 0 auto;
position: relative;
}
.content {
flex: 1 1 auto;
contain: size layout style;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
}

View File

@@ -1,2 +1,3 @@
export const app: string;
export const header: string;
export const content: string;

View File

@@ -1,29 +1,29 @@
@import '~style/helpers.scss';
:global {
// @import '~preact-material-components/Drawer/style.css';
@import '~preact-material-components/List/mdc-list.scss';
// @import '~preact-material-components/Drawer/style.css';
@import '~preact-material-components/List/mdc-list.scss';
}
.drawer {
:global(.mdc-list-item__start-detail) {
margin-right: 16px;
}
:global(.mdc-list-item__start-detail) {
margin-right: 16px;
}
}
.logo {
width: 50%;
width: 50%;
}
.category img {
opacity: .6;
opacity: .6;
}
.bottom {
position: absolute;
bottom: 0;
bottom: constant(safe-area-inset-bottom);
bottom: env(safe-area-inset-bottom);
left: 0;
width: 100%;
position: absolute;
bottom: 0;
bottom: constant(safe-area-inset-bottom);
bottom: env(safe-area-inset-bottom);
left: 0;
width: 100%;
}

View File

@@ -1,18 +1,18 @@
@import '~style/helpers.scss';
:global {
@import '~preact-material-components/Fab/mdc-fab.scss';
@import '~preact-material-components/Fab/mdc-fab.scss';
}
.fab {
position: fixed;
right: 14px;
bottom: 14px;
z-index: 4;
.progress {
width: 24px;
height: 24px;
color: white;
--mdc-theme-primary: #fff;
}
position: fixed;
right: 14px;
bottom: 14px;
z-index: 4;
.progress {
width: 24px;
height: 24px;
color: white;
--mdc-theme-primary: #fff;
}
}

View File

@@ -1,51 +1,52 @@
@import '~style/helpers.scss';
:global {
@import '~preact-material-components/Toolbar/mdc-toolbar.scss';
@import '~preact-material-components/Toolbar/mdc-toolbar.scss';
}
.toolbar {
height: $toolbar-height;
// height: $toolbar-height;
&.minimal {
height: $toolbar-height / 2;
}
&.minimal {
display: none;
// height: $toolbar-height / 2;
}
// > * {
// min-height: 0;
// }
// > * {
// min-height: 0;
// }
}
.fileInput {
position: absolute;
left: 0;
top: -999px;
position: absolute;
left: 0;
top: -999px;
}
.fab {
position: fixed;
display: block;
right: 14px;
bottom: 14px;
// z-index: 999;
// transform: translateZ(0);
position: fixed;
display: block;
right: 14px;
bottom: 14px;
// z-index: 999;
// transform: translateZ(0);
}
.logo {
height: 1em;
height: 1em;
}
.menu {
position: absolute;
top: $toolbar-height;
right: 5px;
position: absolute;
top: $toolbar-height;
right: 5px;
.menuItem {
margin-right: 16px;
}
.menuItem {
margin-right: 16px;
}
}
.title {
padding: 3px 0 0;
font-weight: 300;
font-size: 140%;
padding: 3px 0 0;
font-weight: 300;
font-size: 140%;
}

View File

@@ -1,20 +1,20 @@
@import '~style/helpers.scss';
// :global {
// @import '~preact-material-components/Button/mdc-button.scss';
// // @import '~preact-material-components/Switch/mdc-switch.scss';
// @import '~preact-material-components/Button/mdc-button.scss';
// // @import '~preact-material-components/Switch/mdc-switch.scss';
// }
.home {
padding: 20px;
opacity: 0;
padding: 20px;
opacity: 0;
}
.active {
animation: fadeIn 2s forwards ease 1;
animation: fadeIn 2s forwards ease 1;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
from { opacity: 0; }
to { opacity: 1; }
}

View File

@@ -6,23 +6,11 @@
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#673ab8">
<link rel="manifest" href="/manifest.json">
<!--
<% for (var chunk of webpack.chunks) { %>
<% for (var file of chunk.files) { %>
<% if (htmlWebpackPlugin.options.preload && file.match(/\.(js|css)$/)) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>">
<% } else if (file.match(/manifest\.json$/)) { %>
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath + file %>">
<% } %>
<% } %>
<% } %>
-->
</head>
<body>
<%=
/*require('../config/prerender')()*/
htmlWebpackPlugin.options.prerender()
%>
<div id="app" prerender></div>
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> -->
</body>
</html>

View File

@@ -1,26 +1,26 @@
import { options } from 'preact';
const classNameDescriptor = {
enumerable: false,
configurable: true,
get() {
return this.class;
},
set(value) {
this.class = value;
}
enumerable: false,
configurable: true,
get() {
return this.class;
},
set(value) {
this.class = value;
}
};
let old = options.vnode;
options.vnode = vnode => {
let a = vnode.attributes;
if (a!=null) {
if ('className' in a) {
a.class = a.className;
}
if ('class' in a) {
Object.defineProperty(a, 'className', classNameDescriptor);
}
}
if (old != null) old(vnode);
};
let a = vnode.attributes;
if (a != null) {
if ('className' in a) {
a.class = a.className;
}
if ('class' in a) {
Object.defineProperty(a, 'className', classNameDescriptor);
}
}
if (old != null) old(vnode);
};

View File

@@ -1,26 +1,27 @@
// @import './material-icons.scss';
// @import 'material-components-web/material-components-web';
@import './reset.scss';
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
overflow: hidden;
overscroll-behavior: none;
height: 100%;
width: 100%;
padding: 0;
margin: 0;
overflow: hidden;
overscroll-behavior: none;
}
html {
background: #FAFAFA;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 400;
color: #444;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #FAFAFA;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 400;
color: #444;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.mdc-theme--dark {
background-color: #333;
color: #fff;
background-color: #333;
color: #fff;
}

View File

@@ -1,28 +1,28 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}

View File

@@ -1,12 +1,12 @@
button, a, img, input, select, textarea {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
a, button, img, [inert], .inert {
user-select: none;
-webkit-user-select: none;
user-drag: none;
-webkit-user-drag: none;
touch-callout: none;
-webkit-touch-callout: none;
user-select: none;
-webkit-user-select: none;
user-drag: none;
-webkit-user-drag: none;
touch-callout: none;
-webkit-touch-callout: none;
}

View File

@@ -10,114 +10,114 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const ReplacePlugin = require('webpack-plugin-replace');
const CopyPlugin = require('copy-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
const WatchTimestampsPlugin = require('./config/watch-timestamps-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
function readJson(filename) {
return JSON.parse(fs.readFileSync(filename));
return JSON.parse(fs.readFileSync(filename));
}
module.exports = function(_, env) {
const isProd = env.mode === 'production';
const nodeModules = path.join(__dirname, 'node_modules');
const componentStyleDirs = [
path.join(__dirname, 'src/components'),
path.join(__dirname, 'src/routes')
];
const isProd = env.mode === 'production';
const nodeModules = path.join(__dirname, 'node_modules');
const componentStyleDirs = [
path.join(__dirname, 'src/components'),
path.join(__dirname, 'src/routes')
];
return {
mode: isProd ? 'production' : 'development',
entry: path.join(__dirname, 'config/client-boot.js'),
output: {
filename: isProd ? '[name].[chunkhash:5].js' : '[name].js',
chunkFilename: '[name].chunk.[chunkhash:5].js',
path: path.join(__dirname, 'build'),
publicPath: '/'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss', '.css'],
alias: {
'app-entry-point': path.join(__dirname, 'src/index'),
style: path.join(__dirname, 'src/style')
}
},
resolveLoader: {
alias: {
// async-component-loader returns a wrapper component that waits for the import to load before rendering:
async: path.join(__dirname, 'config/async-component-loader')
}
},
module: {
rules: [
{
test: /\.tsx?$/,
// Ensure typescript is compiled prior to Babel running:
enforce: 'pre',
loader: 'ts-loader',
// Don't transpile anything in node_modules:
exclude: nodeModules,
return {
mode: isProd ? 'production' : 'development',
entry: './src/index',
output: {
filename: isProd ? '[name].[chunkhash:5].js' : '[name].js',
chunkFilename: '[name].chunk.[chunkhash:5].js',
path: path.join(__dirname, 'build'),
publicPath: '/'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss', '.css'],
alias: {
style: path.join(__dirname, 'src/style')
}
},
resolveLoader: {
alias: {
// async-component-loader returns a wrapper component that waits for the import to load before rendering:
async: path.join(__dirname, 'config/async-component-loader')
}
},
module: {
rules: [
{
test: /\.tsx?$/,
// Ensure typescript is compiled prior to Babel running:
enforce: 'pre',
loader: 'ts-loader',
// Don't transpile anything in node_modules:
exclude: nodeModules,
options: {
// Offload type checking to ForkTsCheckerWebpackPlugin for better performance:
transpileOnly: true
}
},
{
test: /\.(tsx?|jsx?)$/,
loader: 'babel-loader',
// Don't respect any Babel RC files found on the filesystem:
options: Object.assign(readJson('.babelrc'), { babelrc: false })
},
{
test: /\.(scss|sass)$/,
loader: 'sass-loader',
// SCSS gets preprocessed, then treated like any other CSS:
enforce: 'pre',
options: {
sourceMap: true,
includePaths: [nodeModules]
}
},
{
test: /\.(scss|sass|css)$/,
// Only enable CSS Modules within `src/{components,routes}/*`
include: componentStyleDirs,
use: [
// In production, CSS is extracted to files on disk. In development, it's inlined into JS:
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{
// This is a fork of css-loader that auto-generates .d.ts files for CSS module imports.
// The result is a definition file with the exported String classname mappings.
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
localIdentName: '[local]__[hash:base64:5]',
namedExport: true,
camelCase: true,
importLoaders: 1,
sourceMap: isProd,
sass: true
}
}
]
},
{
test: /\.(scss|sass|css)$/,
// Process non-modular CSS everywhere *except* `src/{components,routes}/*`
exclude: componentStyleDirs,
use: [
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: isProd
}
}
]
}
]
},
plugins: [
},
{
test: /\.(tsx?|jsx?)$/,
loader: 'babel-loader',
// Don't respect any Babel RC files found on the filesystem:
options: Object.assign(readJson('.babelrc'), { babelrc: false })
},
{
test: /\.(scss|sass)$/,
loader: 'sass-loader',
// SCSS gets preprocessed, then treated like any other CSS:
enforce: 'pre',
options: {
sourceMap: true,
includePaths: [nodeModules]
}
},
{
test: /\.(scss|sass|css)$/,
// Only enable CSS Modules within `src/{components,routes}/*`
include: componentStyleDirs,
use: [
// In production, CSS is extracted to files on disk. In development, it's inlined into JS:
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{
// This is a fork of css-loader that auto-generates .d.ts files for CSS module imports.
// The result is a definition file with the exported String classname mappings.
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
localIdentName: '[local]__[hash:base64:5]',
namedExport: true,
camelCase: true,
importLoaders: 1,
sourceMap: isProd,
sass: true
}
}
]
},
{
test: /\.(scss|sass|css)$/,
// Process non-modular CSS everywhere *except* `src/{components,routes}/*`
exclude: componentStyleDirs,
use: [
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: isProd
}
}
]
}
]
},
plugins: [
// Runs tslint & type checking in a worker pool
new ForkTsCheckerWebpackPlugin({
tslint: true,
@@ -127,140 +127,140 @@ module.exports = function(_, env) {
}),
new ForkTsCheckerNotifierWebpackPlugin({ excludeWarnings: true }),
// Pretty progressbar showing build progress:
new ProgressBarPlugin({
format: '\u001b[90m\u001b[44mBuild\u001b[49m\u001b[39m [:bar] \u001b[32m\u001b[1m:percent\u001b[22m\u001b[39m (:elapseds) \u001b[2m:msg\u001b[22m',
renderThrottle: 100,
summary: false,
clear: true
}),
// Pretty progressbar showing build progress:
new ProgressBarPlugin({
format: '\u001b[90m\u001b[44mBuild\u001b[49m\u001b[39m [:bar] \u001b[32m\u001b[1m:percent\u001b[22m\u001b[39m (:elapseds) \u001b[2m:msg\u001b[22m',
renderThrottle: 100,
summary: false,
clear: true
}),
// Remove old files before outputting a production build:
isProd && new CleanWebpackPlugin([
'assets',
'**/*.{css,js,json,html}'
], {
root: path.join(__dirname, 'build'),
beforeEmit: true
}),
// Remove old files before outputting a production build:
isProd && new CleanWebpackPlugin([
'assets',
'**/*.{css,js,json,html}'
], {
root: path.join(__dirname, 'build'),
beforeEmit: true
}),
// Automatically split code into async chunks.
// See: https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
isProd && new webpack.optimize.SplitChunksPlugin({}),
// Automatically split code into async chunks.
// See: https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
isProd && new webpack.optimize.SplitChunksPlugin({}),
// In production, extract all CSS to produce files on disk, even for
// lazy-loaded CSS chunks. CSS for async chunks is loaded on-demand.
// This is a modern Webpack 4 replacement for ExtractTextPlugin.
// See: https://github.com/webpack-contrib/mini-css-extract-plugin
// See also: https://twitter.com/wsokra/status/970253245733113856
isProd && new MiniCssExtractPlugin({
chunkFilename: '[name].chunk.[contenthash:5].css'
}),
// In production, extract all CSS to produce files on disk, even for
// lazy-loaded CSS chunks. CSS for async chunks is loaded on-demand.
// This is a modern Webpack 4 replacement for ExtractTextPlugin.
// See: https://github.com/webpack-contrib/mini-css-extract-plugin
// See also: https://twitter.com/wsokra/status/970253245733113856
isProd && new MiniCssExtractPlugin({
chunkFilename: '[name].chunk.[contenthash:5].css'
}),
// These plugins fix infinite loop in typings-for-css-modules-loader.
// See: https://github.com/Jimdo/typings-for-css-modules-loader/issues/35
new webpack.WatchIgnorePlugin([
/(c|sc|sa)ss\.d\.ts$/
]),
new WatchTimestampsPlugin([
/(c|sc|sa)ss\.d\.ts$/
]),
// These plugins fix infinite loop in typings-for-css-modules-loader.
// See: https://github.com/Jimdo/typings-for-css-modules-loader/issues/35
new webpack.WatchIgnorePlugin([
/(c|sc|sa)ss\.d\.ts$/
]),
new WatchTimestampsPlugin([
/(c|sc|sa)ss\.d\.ts$/
]),
// For now we're not doing SSR.
new HtmlWebpackPlugin({
filename: path.join(__dirname, 'build/index.html'),
template: '!!ejs-loader!src/index.html',
// template: '!!'+path.join(__dirname, 'config/prerender-loader')+'!src/index.html',
minify: isProd && {
collapseWhitespace: true,
removeScriptTypeAttributes: true,
removeRedundantAttributes: true,
removeStyleLinkTypeAttributes: true,
removeComments: true
},
manifest: readJson('./src/manifest.json'),
inject: true,
compile: true
}),
// For now we're not doing SSR.
new HtmlWebpackPlugin({
filename: path.join(__dirname, 'build/index.html'),
template: '!!ejs-loader!src/index.html',
// template: '!!'+path.join(__dirname, 'config/prerender-loader')+'!src/index.html',
minify: isProd && {
collapseWhitespace: true,
removeScriptTypeAttributes: true,
removeRedundantAttributes: true,
removeStyleLinkTypeAttributes: true,
removeComments: true
},
manifest: readJson('./src/manifest.json'),
inject: true,
compile: true
}),
// Inject <link rel="preload"> for resources
isProd && new PreloadWebpackPlugin(),
// Inject <link rel="preload"> for resources
isProd && new PreloadWebpackPlugin(),
// Inline constants during build, so they can be folded by UglifyJS.
new webpack.DefinePlugin({
// We set node.process=false later in this config.
// Here we make sure if (process && process.foo) still works:
process: '{}'
}),
// Inline constants during build, so they can be folded by UglifyJS.
new webpack.DefinePlugin({
// We set node.process=false later in this config.
// Here we make sure if (process && process.foo) still works:
process: '{}'
}),
// Babel embeds helpful error messages into transpiled classes that we don't need in production.
// Here we replace the constructor and message with a static throw, leaving the message to be DCE'd.
// This is useful since it shows the message in SourceMapped code when debugging.
isProd && new ReplacePlugin({
include: /babel-helper$/,
patterns: [{
regex: /throw\s+(?:new\s+)?((?:Type|Reference)?Error)\s*\(/g,
value: (s, type) => `throw 'babel error'; (`
}]
}),
// Babel embeds helpful error messages into transpiled classes that we don't need in production.
// Here we replace the constructor and message with a static throw, leaving the message to be DCE'd.
// This is useful since it shows the message in SourceMapped code when debugging.
isProd && new ReplacePlugin({
include: /babel-helper$/,
patterns: [{
regex: /throw\s+(?:new\s+)?((?:Type|Reference)?Error)\s*\(/g,
value: (s, type) => `throw 'babel error'; (`
}]
}),
// Copying files via Webpack allows them to be served dynamically by `webpack serve`
new CopyPlugin([
{ from: 'src/manifest.json', to: 'manifest.json' },
{ from: 'src/assets', to: 'assets' }
]),
// Copying files via Webpack allows them to be served dynamically by `webpack serve`
new CopyPlugin([
{ from: 'src/manifest.json', to: 'manifest.json' },
{ from: 'src/assets', to: 'assets' }
]),
// For production builds, output module size analysis to build/report.html
isProd && new BundleAnalyzerPlugin({
analyzerMode: 'static',
defaultSizes: 'gzip',
openAnalyzer: false
}),
// For production builds, output module size analysis to build/report.html
isProd && new BundleAnalyzerPlugin({
analyzerMode: 'static',
defaultSizes: 'gzip',
openAnalyzer: false
}),
// Generate a ServiceWorker using Workbox.
isProd && new WorkboxPlugin.GenerateSW({
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
// allow for offline client-side routing:
navigateFallback: '/',
navigateFallbackBlacklist: [/\.[a-z0-9]+$/i]
})
].filter(Boolean), // Filter out any falsey plugin array entries.
// Generate a ServiceWorker using Workbox.
isProd && new WorkboxPlugin.GenerateSW({
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
// allow for offline client-side routing:
navigateFallback: '/',
navigateFallbackBlacklist: [/\.[a-z0-9]+$/i]
})
].filter(Boolean), // Filter out any falsey plugin array entries.
// Turn off various NodeJS environment polyfills Webpack adds to bundles.
// They're supposed to be added only when used, but the heuristic is loose
// (eg: existence of a variable called setImmedaite in any scope)
node: {
console: false,
// Keep global, it's just an alias of window and used by many third party modules:
global: true,
// Turn off process to avoid bundling a nextTick implementation:
process: false,
// Inline __filename and __dirname values:
__filename: 'mock',
__dirname: 'mock',
// Never embed a portable implementation of Node's Buffer module:
Buffer: false,
// Never embed a setImmediate implementation:
setImmediate: false
},
// Turn off various NodeJS environment polyfills Webpack adds to bundles.
// They're supposed to be added only when used, but the heuristic is loose
// (eg: existence of a variable called setImmedaite in any scope)
node: {
console: false,
// Keep global, it's just an alias of window and used by many third party modules:
global: true,
// Turn off process to avoid bundling a nextTick implementation:
process: false,
// Inline __filename and __dirname values:
__filename: 'mock',
__dirname: 'mock',
// Never embed a portable implementation of Node's Buffer module:
Buffer: false,
// Never embed a setImmediate implementation:
setImmediate: false
},
devServer: {
// Any unmatched request paths will serve static files from src/*:
contentBase: path.join(__dirname, 'src'),
inline: true,
hot: true,
// Request paths not ending in a file extension serve index.html:
historyApiFallback: true,
// Don't output server address info to console on startup:
noInfo: true,
// Suppress forwarding of Webpack logs to the browser console:
clientLogLevel: 'none',
// Supress the extensive stats normally printed after a dev build (since sizes are mostly useless):
stats: 'minimal',
// Don't embed an error overlay ("redbox") into the client bundle:
overlay: false
}
};
devServer: {
// Any unmatched request paths will serve static files from src/*:
contentBase: path.join(__dirname, 'src'),
inline: true,
hot: true,
// Request paths not ending in a file extension serve index.html:
historyApiFallback: true,
// Don't output server address info to console on startup:
noInfo: true,
// Suppress forwarding of Webpack logs to the browser console:
clientLogLevel: 'none',
// Supress the extensive stats normally printed after a dev build (since sizes are mostly useless):
stats: 'minimal',
// Don't embed an error overlay ("redbox") into the client bundle:
overlay: false
}
};
};