Skip to content

Commit

Permalink
#84 automatic critical css generation - work ing progress
Browse files Browse the repository at this point in the history
  • Loading branch information
tbela99 committed Oct 27, 2021
1 parent 2bf5588 commit b188238
Show file tree
Hide file tree
Showing 55 changed files with 1,549 additions and 269 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change History

# 3.0

- @tbela99 #138 AVIF image support: automatically convert images to AVIF format when the browser advertise it and the dg support is enabled
- @tbela99 #84 Automatically generate critical css path. no more parameter are required

# 2.11.0

- @cbahiana-sd Added info on enabling zlib.output_compression 495b84d
Expand Down
2 changes: 2 additions & 0 deletions build.sh
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ fail() {
#
#
# build config files
npm run rollup-config
npm run terser-config
# process es6+ deps
node rollup.config.js
# minify
Expand Down
14 changes: 8 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"require": {
"lordelph/icofileloader": "^2.0",
"tbela99/css": "dev-php56-backport-dev",
"ext-gd": "*",
"mck89/peast": "^1.13"
}
"require": {
"lordelph/icofileloader": "^2.0",
"tbela99/css": "dev-php56-backport",
"mck89/peast": "^1.13",
"ext-gd": "*",
"ext-json": "*",
"ext-sodium": "*"
}
}
19 changes: 19 additions & 0 deletions config/rollup/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ export const libImages = {
}
};

// export const critical = {
// input: "./worker/src/critical/critical.js",
// output: {
//
// name: 'critical',
// file:"./worker/dist/critical.js",
// format: "iife"
// }
// };

export const criticalExtract = {
input: "./worker/src/critical/extract.js",
output: {

file:"./worker/dist/critical-extract.js",
format: "iife"
}
};

export const serviceworker = {
input: "worker/src/index.js",
output: {
Expand Down
62 changes: 58 additions & 4 deletions config/terser/terser.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

const preamble = "/* do not edit this file! */";
const ECMA_VERSION = 5;
const ECMA_VERSION = 6;

const compress = {
// ecma: ECMA_VERSION,
Expand Down Expand Up @@ -50,7 +50,7 @@ const minify = {
}
};

const imagesOverride = {
const topLevelCompress = {

compress: {

Expand Down Expand Up @@ -102,6 +102,59 @@ export const imageLoaderMin = {
}
};

export const critical = {
input: "./worker/src/critical/critical.js",
output: "./worker/dist/critical.js",
config: {
// ie8: true,
ecma: ECMA_VERSION,
output,
warnings: true
}
};

export const criticalMin = {
input: "./worker/dist/critical.js",
output: "./worker/dist/critical.min.js",
config: {
...minify,
...topLevelCompress,
// ie8: true,
ecma: ECMA_VERSION // specify one of: 5, 6, 7 or 8
}
};

export const criticalFontLoader = {
input: "./worker/src/critical/fontloader.js",
output:"./worker/dist/fontloader.js",
config: {
// ie8: true,
ecma: ECMA_VERSION,
output,
warnings: true
}
};

export const criticalFontLoaderMin = {
input: "./worker/dist/fontloader.js",
output:"./worker/dist/fontloader.min.js",
config: {
...minify,
// ie8: true,
ecma: ECMA_VERSION // specify one of: 5, 6, 7 or 8
}
};

export const criticalExtractMin = {
input: "./worker/dist/critical-extract.js",
output: "./worker/dist/critical-extract.min.js",
config: {
...minify,
// ie8: true,
ecma: ECMA_VERSION // specify one of: 5, 6, 7 or 8
}
};

export const bgStylesMin = {
input: "./bgstyles.js",
output: "./bgstyles.min.js",
Expand All @@ -127,7 +180,7 @@ export const libReadyMin = {
output: "./js/dist//lib.ready.min.js",
config: {
...minify,
...imagesOverride,
...topLevelCompress,
ecma: ECMA_VERSION
}
};
Expand All @@ -137,7 +190,7 @@ export const libImageMin = {
output: "./js/dist//lib.images.min.js",
config: {
...minify,
...imagesOverride,
...topLevelCompress,
ecma: ECMA_VERSION
}
};
Expand Down Expand Up @@ -174,6 +227,7 @@ export const browserPrefetchMin = {
output: "./worker/dist/browser.prefetch.min.js",
config: {
...minify,
...topLevelCompress,
ecma: ECMA_VERSION
}
};
Expand Down
10 changes: 5 additions & 5 deletions css/images.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.image-placeholder-lqip {
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='4');
filter: blur(4px);
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='0.3');
filter: blur(0.3rem);
}
.image-placeholder-loaded {
transform: translateX(100%);
Expand All @@ -9,7 +9,7 @@
position: relative;
display: inline-block;
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='0');
filter: blur(0px);
filter: blur(0rem);
transition: filter 0.2s ease-out;
}
.image-placeholder-wrapper > img {
Expand All @@ -28,8 +28,8 @@
max-height: 100%;
}
.image-placeholder-wrapper :not(.image-placeholder-complete) {
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='4');
filter: blur(4px);
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='0.3');
filter: blur(0.3rem);
}
.image-placeholder-wrapper .image-placeholder-opacity {
transition: opacity 0.2s ease-out;
Expand Down
4 changes: 2 additions & 2 deletions css/images.less
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.blur-mixin (@value: 4) {
.blur-mixin (@value: .3, @unit: 'rem') {
& {
-ms-filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='@{value}'); // filter: url(#blur-lqip);
filter: blur(~"@{value}px");
filter: blur(~"@{value}@{unit}");
}
}

Expand Down
110 changes: 110 additions & 0 deletions gzip.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Gzip\GZipHelper as GZipHelper;
use Joomla\CMS\Factory as JFactory;
use Joomla\Registry\Registry as Registry;
use TBela\CSS\Parser;

class PlgSystemGzip extends JPlugin
{
Expand Down Expand Up @@ -298,6 +299,113 @@ public function onAfterInitialise()
$this->options = json_decode(json_encode($options), JSON_OBJECT_AS_ARRAY);
}

if ($_SERVER['REQUEST_METHOD'] == 'POST' && $_SERVER['REQUEST_URI'] == GZipHelper::CRITICAL_PATH_URL && isset($_SERVER['HTTP_X_SIGNATURE'])) {

$dimensions = preg_split('#\s+#s', $this->options['criticalcssviewports'], -1, PREG_SPLIT_NO_EMPTY);

usort($dimensions, function ($a, $b) {

$a = +explode('x', $a)[0];
$b = +explode('x', $b)[0];

return $b - $a;
});

$signatures = explode('.', $_SERVER['HTTP_X_SIGNATURE']);

$raw = file_get_contents('php://input');
$post = json_decode($raw, JSON_OBJECT_AS_ARRAY);

if (count($signatures) != 2 ||
!is_array($post) ||
!isset($post['url']) ||
!isset($post['css']) ||
!isset($post['fonts']) ||
!is_array($post['fonts']) ||
!isset($_SERVER['HTTP_X_SIGNATURE']) ||
!isset($post['dimension']) ||
!in_array($post['dimension'], $dimensions)) {

http_response_code(400);
exit;
}

$data = [

'url' => $post['url'],
'dimensions' => $dimensions
];

// compute the key used to sign data
$hash = hash_hmac('sha256', $app->getTemplate().json_encode($data), $this->options['expiring_links']['secret']);

if ($_SERVER['HTTP_X_SIGNATURE'] != $signatures[0].'.'.hash('sha256', $signatures[0].$raw)) {

http_response_code(400);
exit;
}

$raw_message = hex2bin($signatures[0]);
$nonce = substr($raw_message, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted_message2 = substr($raw_message, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$decrypted_message = sodium_crypto_secretbox_open($encrypted_message2, $nonce, hex2bin($hash));

$encrypted_data = json_decode($decrypted_message, JSON_OBJECT_AS_ARRAY);

if (!is_array($encrypted_data) ||
!isset($encrypted_data['key']) ||
$encrypted_data['key'] != $hash ||
!isset($encrypted_data['duration'])) {

http_response_code(400);
exit;
}

if ($encrypted_data['duration'] > time()) {

http_response_code(410);
exit;
}

$path = JPATH_SITE . '/cache/z/critical/' . $_SERVER['SERVER_NAME'] . '/';

if (!is_dir($path)) {

$old_mask = umask();

umask(022);
mkdir($path, 0755, true);
umask($old_mask);
}

header('Content-Type: application/json; charset=utf-8');
file_put_contents($path.'/'.$hash.'_'.$post['dimension'].'.css', new Parser($post['css']));

$fonts = [];

foreach ($post['fonts'] as $font) {

$fonts[md5(json_encode($font))] = $font;
}

$fontFile = $path.'/'.$hash.'_'.$post['dimension'].'.php';

if (!empty($fonts)) {

file_put_contents($fontFile, '<?php'."\n
defined('JPATH_PLATFORM') or die;
\$fonts = ".var_export($fonts, true).';');
}

else if (is_file($fontFile)) {

unlink($fontFile);
}

echo 1;
exit;
}

if (!is_file($file)) {

$this->updateServiceWorker($this->options);
Expand Down Expand Up @@ -675,6 +783,7 @@ public function onAfterRender()
$options = $this->options;

$options['webroot'] = JURI::root(true) . '/';
$options['request_uri'] = $_SERVER['REQUEST_URI'];
$options['scheme'] = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 'https' : 'http';

if (!empty($options['jsignore'])) {
Expand Down Expand Up @@ -717,6 +826,7 @@ public function onAfterRender()
$options['cssremove'] = [];
}

$options['template'] = $app->getTemplate();
$options['uri_root'] = JUri::root(true);

if ($options['uri_root'] === '') {
Expand Down
7 changes: 4 additions & 3 deletions gzip.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<license>Released under dual license LGPL v3 | MIT</license>
<authorEmail>contact@tbela.net</authorEmail>
<authorUrl>https://tbela.net</authorUrl>
<version>2.11.0</version>
<version>3.0-alpha1</version>
<description>PLG_SYSTEM_GZIP_XML_DESCRIPTION</description>
<files>
<folder>docs</folder>
Expand Down Expand Up @@ -373,8 +373,9 @@
<option value="1">JYes</option>
<option value="0">JNo</option>
</field>
<field name="criticalcssclass" label="PLG_GZIP_FIELD_CRITICALCSS_CLASS_LABEL" description="PLG_GZIP_FIELD_CRITICALCSS_CLASS_DESCRIPTION" hint="PLG_GZIP_FIELD_CRITICALCSS_CLASS_HINT" type="textarea" rows="5" cols="15" default="" />
<field name="criticalcss" label="PLG_GZIP_FIELD_CRITICALCSS_LABEL" description="PLG_GZIP_FIELD_CRITICALCSS_DESCRIPTION" hint="PLG_GZIP_FIELD_CRITICALCSS_HINT" type="textarea" rows="5" cols="15" default="" />
<field name="criticalcssviewports" label="PLG_GZIP_FIELD_CRITICALCSS_VIEWPORT_LABEL" description="PLG_GZIP_FIELD_CRITICALCSS_VIEWPORT_DESCRIPTION" hint="PLG_GZIP_FIELD_CRITICALCSS_VIEWPORT_HINT" type="textarea" rows="5" cols="15" default="800x600" />
<!-- <field name="criticalcssclass" label="PLG_GZIP_FIELD_CRITICALCSS_CLASS_LABEL" description="PLG_GZIP_FIELD_CRITICALCSS_CLASS_DESCRIPTION" hint="PLG_GZIP_FIELD_CRITICALCSS_CLASS_HINT" type="textarea" rows="5" cols="15" default="" />-->
<!-- <field name="criticalcss" label="PLG_GZIP_FIELD_CRITICALCSS_LABEL" description="PLG_GZIP_FIELD_CRITICALCSS_DESCRIPTION" hint="PLG_GZIP_FIELD_CRITICALCSS_HINT" type="textarea" rows="5" cols="15" default="" />-->
</fields>
</fieldset>
<fieldset name="pwa_app" label="Service Worker">
Expand Down
2 changes: 2 additions & 0 deletions helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class GZipHelper
const regexAttr = '~([\r\n\t ])?([a-zA-Z0-9:-]+)((=(["\'])(.*?)\5)|([\r\n\t ]|$))?~m'; #s
const regexUrl = '#url\(([^)]+)\)#';

const CRITICAL_PATH_URL = '/gzip-critical-path';

/**
* @var string regex
* @since version
Expand Down
Loading

0 comments on commit b188238

Please sign in to comment.