Correctly inlining the global loader style
parent
61da22895f
commit
503ca5db8b
|
@ -1,3 +1,3 @@
|
||||||
import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./index.scss";
|
import "./index.scss";
|
||||||
import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./loader.scss";
|
import "./loader.scss";
|
||||||
import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./overlay.css";
|
import "./overlay.css";
|
|
@ -1,8 +1,9 @@
|
||||||
$setup-time-normal: 80s / 24; /* 24 frames / sec; the initial sequence is 80 frames */
|
:global {
|
||||||
$setup-time-halloween: 323s / 24;
|
$setup-time-normal: 80s / 24; /* 24 frames / sec; the initial sequence is 80 frames */
|
||||||
$loop-time-halloween: 25s / 24;
|
$setup-time-halloween: 323s / 24;
|
||||||
|
$loop-time-halloween: 25s / 24;
|
||||||
|
|
||||||
#loader-overlay {
|
#loader-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
@ -116,24 +117,47 @@ $loop-time-halloween: 25s / 24;
|
||||||
|
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Automated loader timeout */
|
||||||
|
#loader-overlay:not(.initialized) + #critical-load:not(.shown) {
|
||||||
|
display: block !important;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
animation: loader-setup-timeout 0s ease-in $setup-time-normal forwards;
|
||||||
|
|
||||||
|
.error::before {
|
||||||
|
content: 'Failed to startup loader!';
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail::before {
|
||||||
|
content: 'Lookup the console for more details';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-width: 850px) {
|
@media all and (max-width: 850px) {
|
||||||
|
:global {
|
||||||
#loader-overlay .container {
|
#loader-overlay .container {
|
||||||
transform: scale(.5);
|
transform: scale(.5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-height: 700px) {
|
@media all and (max-height: 700px) {
|
||||||
|
:global {
|
||||||
#loader-overlay .container {
|
#loader-overlay .container {
|
||||||
transform: scale(.5);
|
transform: scale(.5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-width: 400px) {
|
@media all and (max-width: 400px) {
|
||||||
|
:global {
|
||||||
#loader-overlay .container {
|
#loader-overlay .container {
|
||||||
transform: scale(.3);
|
transform: scale(.3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes loader-initial-sequence {
|
@keyframes loader-initial-sequence {
|
||||||
|
@ -192,23 +216,6 @@ $loop-time-halloween: 25s / 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Automated loader timeout */
|
|
||||||
#loader-overlay:not(.initialized) + #critical-load:not(.shown) {
|
|
||||||
display: block !important;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
animation: loader-setup-timeout 0s ease-in $setup-time-normal forwards;
|
|
||||||
|
|
||||||
.error::before {
|
|
||||||
content: 'Failed to startup loader!';
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail::before {
|
|
||||||
content: 'Lookup the console for more details';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes loader-setup-timeout {
|
@keyframes loader-setup-timeout {
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#overlay-no-js, #critical-load {
|
:global {
|
||||||
|
#overlay-no-js, #critical-load {
|
||||||
z-index: 100000000;
|
z-index: 100000000;
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -27,9 +28,9 @@
|
||||||
&.shown {
|
&.shown {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#critical-load {
|
#critical-load {
|
||||||
img {
|
img {
|
||||||
height: 12em
|
height: 12em
|
||||||
}
|
}
|
||||||
|
@ -43,10 +44,10 @@
|
||||||
color: #696363;
|
color: #696363;
|
||||||
margin-top: .5em
|
margin-top: .5em
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@media (max-height: 750px) {
|
@media (max-height: 750px) {
|
||||||
#critical-load .container {
|
#critical-load .container {
|
||||||
top: unset;
|
top: unset;
|
||||||
}
|
}
|
||||||
|
@ -61,4 +62,5 @@
|
||||||
#critical-load.shown {
|
#critical-load.shown {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -66,7 +66,6 @@
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"potpack": "^1.0.1",
|
"potpack": "^1.0.1",
|
||||||
"raw-loader": "^4.0.0",
|
"raw-loader": "^4.0.0",
|
||||||
"react-dev-utils": "^11.0.4",
|
|
||||||
"sass": "1.22.10",
|
"sass": "1.22.10",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"sha256": "^0.2.0",
|
"sha256": "^0.2.0",
|
||||||
|
|
|
@ -11,7 +11,7 @@ const webpack = require("webpack");
|
||||||
|
|
||||||
import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator";
|
import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator";
|
||||||
const ManifestGenerator = require("./webpack/ManifestPlugin");
|
const ManifestGenerator = require("./webpack/ManifestPlugin");
|
||||||
const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
|
const HtmlWebpackInlineSourcePlugin = require("./webpack/HtmlWebpackInlineSource");
|
||||||
|
|
||||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
@ -155,7 +155,7 @@ export const config = async (target: "web" | "client"): Promise<Configuration &
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
generateIndexPlugin(target),
|
generateIndexPlugin(target),
|
||||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.*/]),
|
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin),
|
||||||
].filter(e => !!e),
|
].filter(e => !!e),
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
const escapeRegex = require('escape-string-regexp');
|
||||||
|
const path = require('path');
|
||||||
|
const slash = require('slash');
|
||||||
|
const sourceMapUrl = require('source-map-url');
|
||||||
|
|
||||||
|
function HtmlWebpackInlineSourcePlugin (htmlWebpackPlugin) {
|
||||||
|
this.htmlWebpackPlugin = htmlWebpackPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlWebpackInlineSourcePlugin.prototype.apply = function (compiler) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// Hook into the html-webpack-plugin processing
|
||||||
|
compiler.hooks.compilation.tap('html-webpack-inline-source-plugin', compilation => {
|
||||||
|
self.htmlWebpackPlugin
|
||||||
|
.getHooks(compilation)
|
||||||
|
.alterAssetTagGroups.tapAsync('html-webpack-inline-source-plugin', (htmlPluginData, callback) => {
|
||||||
|
if (!htmlPluginData.plugin.options.inlineSource) {
|
||||||
|
return callback(null, htmlPluginData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const regexStr = htmlPluginData.plugin.options.inlineSource;
|
||||||
|
const result = self.processTags(compilation, regexStr, htmlPluginData);
|
||||||
|
callback(null, result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlWebpackInlineSourcePlugin.prototype.processTags = function (compilation, regexStr, pluginData) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
const bodyTags = [];
|
||||||
|
const headTags = [];
|
||||||
|
|
||||||
|
const regex = new RegExp(regexStr);
|
||||||
|
const filename = pluginData.plugin.options.filename;
|
||||||
|
|
||||||
|
pluginData.headTags.forEach(function (tag) {
|
||||||
|
headTags.push(self.processTag(compilation, regex, tag, filename));
|
||||||
|
});
|
||||||
|
|
||||||
|
pluginData.bodyTags.forEach(function (tag) {
|
||||||
|
bodyTags.push(self.processTag(compilation, regex, tag, filename));
|
||||||
|
});
|
||||||
|
|
||||||
|
return { headTags: headTags, bodyTags: bodyTags, plugin: pluginData.plugin, outputName: pluginData.outputName };
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlWebpackInlineSourcePlugin.prototype.resolveSourceMaps = function (compilation, assetName, asset) {
|
||||||
|
let source = asset.source();
|
||||||
|
const out = compilation.outputOptions;
|
||||||
|
// Get asset file absolute path
|
||||||
|
const assetPath = path.join(out.path, assetName);
|
||||||
|
// Extract original sourcemap URL from source string
|
||||||
|
if (typeof source !== 'string') {
|
||||||
|
source = source.toString();
|
||||||
|
}
|
||||||
|
const mapUrlOriginal = sourceMapUrl.getFrom(source);
|
||||||
|
// Return unmodified source if map is unspecified, URL-encoded, or already relative to site root
|
||||||
|
if (!mapUrlOriginal || mapUrlOriginal.indexOf('data:') === 0 || mapUrlOriginal.indexOf('/') === 0) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
// Figure out sourcemap file path *relative to the asset file path*
|
||||||
|
const assetDir = path.dirname(assetPath);
|
||||||
|
const mapPath = path.join(assetDir, mapUrlOriginal);
|
||||||
|
const mapPathRelative = path.relative(out.path, mapPath);
|
||||||
|
// Starting with Node 6, `path` module throws on `undefined`
|
||||||
|
const publicPath = out.publicPath || '';
|
||||||
|
// Prepend Webpack public URL path to source map relative path
|
||||||
|
// Calling `slash` converts Windows backslashes to forward slashes
|
||||||
|
const mapUrlCorrected = slash(path.join(publicPath, mapPathRelative));
|
||||||
|
// Regex: exact original sourcemap URL, possibly '*/' (for CSS), then EOF, ignoring whitespace
|
||||||
|
const regex = new RegExp(escapeRegex(mapUrlOriginal) + '(\\s*(?:\\*/)?\\s*$)');
|
||||||
|
// Replace sourcemap URL and (if necessary) preserve closing '*/' and whitespace
|
||||||
|
return source.replace(regex, function (match, group) {
|
||||||
|
return mapUrlCorrected + group;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlWebpackInlineSourcePlugin.prototype.processTag = function (compilation, regex, tag, filename) {
|
||||||
|
let assetUrl;
|
||||||
|
let preTag = tag;
|
||||||
|
|
||||||
|
// inline js
|
||||||
|
if (tag.tagName === 'script' && tag.attributes && regex.test(tag.attributes.src)) {
|
||||||
|
assetUrl = tag.attributes.src;
|
||||||
|
tag = {
|
||||||
|
tagName: 'script',
|
||||||
|
closeTag: true,
|
||||||
|
attributes: {
|
||||||
|
type: 'text/javascript'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// inline css
|
||||||
|
} else if (tag.tagName === 'link' && regex.test(tag.attributes.href)) {
|
||||||
|
assetUrl = tag.attributes.href;
|
||||||
|
tag = {
|
||||||
|
tagName: 'style',
|
||||||
|
closeTag: true,
|
||||||
|
attributes: {
|
||||||
|
type: 'text/css'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetUrl) {
|
||||||
|
// Strip public URL prefix from asset URL to get Webpack asset name
|
||||||
|
const publicUrlPrefix = compilation.outputOptions.publicPath || '';
|
||||||
|
// if filename is in subfolder, assetUrl should be prepended folder path
|
||||||
|
if (path.basename(filename) !== filename) {
|
||||||
|
assetUrl = path.dirname(filename) + '/' + assetUrl;
|
||||||
|
}
|
||||||
|
const assetName = path.posix.relative(publicUrlPrefix, assetUrl);
|
||||||
|
const asset = getAssetByName(compilation.assets, assetName);
|
||||||
|
if (compilation.assets[assetName] !== undefined) {
|
||||||
|
const updatedSource = this.resolveSourceMaps(compilation, assetName, asset);
|
||||||
|
tag.innerHTML = (tag.tagName === 'script') ? updatedSource.replace(/(<)(\/script>)/g, '\\x3C$2') : updatedSource;
|
||||||
|
}else{
|
||||||
|
return preTag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getAssetByName (assests, assetName) {
|
||||||
|
for (let key in assests) {
|
||||||
|
if (assests.hasOwnProperty(key)) {
|
||||||
|
let processedKey = path.posix.relative('', key);
|
||||||
|
if (processedKey === assetName) {
|
||||||
|
return assests[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = HtmlWebpackInlineSourcePlugin;
|
Loading…
Reference in New Issue