Skip to content

Commit

Permalink
test: add test for lazy loading CSS using fetch and document.adoptedS…
Browse files Browse the repository at this point in the history
…tyleSheets
  • Loading branch information
webdiscus committed Apr 4, 2024
1 parent 970f732 commit 6717ea1
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 14 deletions.
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate)
- [How to inline JS in HTML](#recipe-inline-js)
- [How to inline SVG, PNG images in HTML](#recipe-inline-image)
- [How to resolve source assets in an attribute containing JSON value](#recipe-resolve-attr-json)
- [How to load CSS file dynamically](#recipe-dynamic-load-css)
- [How to load CSS file dynamically](#recipe-dynamic-load-css) (lazy loading CSS)
- [How to load JS and CSS from `node_modules` in template](#recipe-load-js-css-from-node-modules)
- [How to import CSS or SCSS from `node_modules` in SCSS](#recipe-import-style-from-node-modules)
- [How to process a PHP template](#recipe-preprocessor-php)
Expand Down Expand Up @@ -2417,7 +2417,7 @@ Possible values:
- `false` - disable minification
- `true` - enable minification with default options
- `auto` - in `development` mode disable minification, in `production` mode enable minification with default options,
- `'auto'` - in `development` mode disable minification, in `production` mode enable minification with default options,
use [minifyOptions](#option-minify-options) to customize options
- `{}` - enable minification with custom options, this object are merged with `default options`\
see [options reference](https://github.com/terser/html-minifier-terser#options-quick-reference)
Expand All @@ -2428,7 +2428,7 @@ Possible values:
Type: `Object` Default: `null`
When the [minify](#option-minify) option is set to `auto`, you can configure minification options using the `minifyOptions`.
When the [minify](#option-minify) option is set to `'auto'` or `true`, you can configure minification options using the `minifyOptions`.
#### [↑ back to contents](#contents)
Expand Down Expand Up @@ -5209,26 +5209,47 @@ The custom attribute will contains in the generated HTML the resolved output ass
## How to load CSS file dynamically
For dynamic file loading, we need the output filename of extracted CSS from a source style file.
To get the CSS output filename in JavaScript, you can use the `url` query in `require()` function:
To get the CSS output filename in JavaScript, you can use the `url` query:
```js
const cssFile = require('./style.scss?url');
import cssUrl from './style.scss?url';
// - OR -
const cssUrl = require('./style.scss?url');
```
Where the `./style.scss` is the source SCSS file relative to the JavaScript file.
To load a CSS file dynamically, you can use the function:
To load a CSS file dynamically, you can use following function:
```js
function loadCSS(file) {
import cssUrl from './style.scss?url';

function loadCSS(url) {
const style = document.createElement('link');
style.href = file;
style.href = url;
style.rel = 'stylesheet';
document.head.appendChild(style);
}

const cssFile = require('./style.scss?url');
loadCSS(cssFile);
loadCSS(cssUrl);
```
The CSS will be extracted into separate file and the `cssFile` variable will contains the CSS output filename.
The CSS will be extracted into separate file and the `cssUrl` variable will contains the CSS output filename.
Since 2023, many browsers support the modern way to add the stylesheets into DOM without creating the `link` tag.
```js
import cssUrl from './style.scss?url';

async function loadCSS(url) {
const response = await fetch(url);
const css = await response.text();
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);
document.adoptedStyleSheets = [sheet];
}

loadCSS(cssUrl);
```
See the [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets#browser_compatibility).
#### [↑ back to contents](#contents)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ module.exports = {
entry: {
// Test case multiple chunks with same filename:
// - the `main.css` file is defined here, in entry point
// - the same `main.css` file is defined in `index.pug`
// - the same `main.css` file is defined in `index.html`

// Note: this use case has no sense and should not be used!
// Specify all scripts and styles directly in Pug.
// Specify all scripts and styles directly in HTML.

index: './src/index.html',

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions test/cases/js-import-css-lazy-url-fetch/expected/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link href="favicon.edda23bf.png" rel="icon">
<link href="style.7f152e84.css" rel="stylesheet" />
<script src="main.js" defer></script>
</head>
<body>
<h1>Hello World!</h1>
<p class="lazy">Lazy load CSS</p>
</body>
</html>
1 change: 1 addition & 0 deletions test/cases/js-import-css-lazy-url-fetch/expected/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* extracted by HTMLBundler CSSLoader */.lazy{color:green}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1{color:red}
13 changes: 13 additions & 0 deletions test/cases/js-import-css-lazy-url-fetch/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link href="@images/favicons/favicon.png" rel="icon">
<link href="./style.scss" rel="stylesheet" />
<script src="main.js" defer></script>
</head>
<body>
<h1>Hello World!</h1>
<p class="lazy">Lazy load CSS</p>
</body>
</html>
40 changes: 40 additions & 0 deletions test/cases/js-import-css-lazy-url-fetch/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import cssUrl from './style-dynamic.scss?url';

// universal way
function lazyLoad(url) {
const style = document.createElement('link');
style.rel = 'stylesheet';
style.href = url;
document.head.appendChild(style);
console.log('lazyLoad: ', { cssUrl });
}

// Using fetch and document.adoptedStyleSheets
// Browser compatibility (since early 2023):
// https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets#browser_compatibility

// modern way, using promise
function lazyLoad2(url) {
fetch(url).then((response) => {
response.text().then((css) => {
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);
document.adoptedStyleSheets = [sheet];
console.log('lazyLoad2: ', { cssUrl });
});
});
}

// modern way, using async await
async function lazyLoad3(url) {
const response = await fetch(url);
const css = await response.text();
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);
document.adoptedStyleSheets = [sheet];
console.log('lazyLoad3: ', { cssUrl });
}

//lazyLoad(cssUrl);
//lazyLoad2(cssUrl);
lazyLoad3(cssUrl);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$color: green;
.lazy {
color: $color;
}
4 changes: 4 additions & 0 deletions test/cases/js-import-css-lazy-url-fetch/src/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$color: red;
h1 {
color: $color;
}
47 changes: 47 additions & 0 deletions test/cases/js-import-css-lazy-url-fetch/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const path = require('path');
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');

module.exports = {
mode: 'production',

output: {
path: path.join(__dirname, 'dist/'),
},

resolve: {
alias: {
'@images': path.join(__dirname, '../../fixtures/images'),
},
},

plugins: [
new HtmlBundlerPlugin({
entry: {
index: './src/index.html',
},
css: {
filename: '[name].[contenthash:8].css',
},
// test disable - OK
preprocessor: false,
// test output of lazy loaded CSS file
verbose: true,
}),
],

module: {
rules: [
{
test: /\.s?css$/,
use: ['css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|ico|svg)$/,
type: 'asset/resource',
generator: {
filename: '[name].[hash:8][ext]',
},
},
],
},
};
2 changes: 1 addition & 1 deletion test/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,8 @@ describe('import styles in JavaScript', () => {
});

describe('import lazy styles in JavaScript', () => {
// TODO: yet experimental, undocumented
test('lazy url in js', () => compareFiles('js-import-css-lazy-url'));
test('lazy load CSS in js using fetch', () => compareFiles('js-import-css-lazy-url-fetch'));
});

describe('CSS source map', () => {
Expand Down

0 comments on commit 6717ea1

Please sign in to comment.