Open GMartigny opened 3 years ago
Yes, but I think we can implement extract
option for this loader
Even better ! Should I change the issue description ?
Yes, let's change it
Very interested to see this feature. I was trying to extract image, style and js, but keep getting error on those.
Is there a way to make extraction work at present?
up
Is there currently any way or a work around to export to HTML files? The instructions in the readme don't seem to work, probably due to extract-loader
being unmaintained and incompatible.
My use-case is pretty simple. I have a bunch of mjml files and I want to use html-loader
to parse each mjml file and and replace image source urls and srcsets to point to image assets that have been minified and renamed into a hashed filename to be deployed on a CDN. I want to use the html-loader
to parse the files, insert the correct urls into the file and export the file back as mjml
. I was able use html-loader
's custom tags configuration to deal with the parsing and rewriting of URLs, but there doesn't seem to be anyway to export the result as an html file.
What is the progress?
Somebody can provide example how you use html-loader
and need extract, I have two solutions here, but they are different and can be used for different things, so I want to see the most popular usage
A simple example from Webpack 4:
{
test: /\.ejs$/i,
exclude: /node_modules/,
use: [
{
loader: 'ejs-loader',
options: {
variable: 'data',
}
},
'extract-loader',
'html-loader',
]
}
html-loader
to replace the paths to the assets in the EJS templateejs-loader
to convert a text template into an object (in this case, the EJS template engine from lodash is used)ejs-loader
is used last because exported object from the EJS templating engine is imported somewhere, and is called with data from the backend.
Something like this:
// template.ejs
Hello, <%- data.name %>!
<% _.forEach(data.items, function (item) { %>
<div>Row - <%- item %></div>
<% }) %>
// view.js
import helloTemplate from 'template.ejs';
let response = {name: 'John', items: ['foo', 'bar']};
$('.body').append(helloTemplate(response));
But most likely this is still unrealizable in the latest version of html-loader
, since EJS template is not a valid HTML and contains specific tags.
I have a html
file in my targets and would like to process it, save to file and extract images (img
src
tags) to separate directory.
<html>
<head>
<link href="main.css" type="text/css" rel="stylesheet">
</head>
<body>
<img src="hi.jpg">
</body>
</html>
Solution, described in extract-loader
readme is not working (anymore):
{
test: /\.html$/,
type: 'asset/resource',
use: [
'extract-loader',
{
loader: "html-loader",
options: {
esModules: false
}
}
]
},
Apparently, extract-loader
tries to extract hi.jpg
as a ES module and fails.
@pseusys Why don't use main.css
as entry point (it will be better optimized and compressed)?
@StudioMaX Weird, I think ejs-loader
can (should) support src
/srcset
/etc resolving
@alexander-akait because image is referenced as src
attribute of img
tag in html, and not in CSS.
As far as I know, one cannot set src
via CSS. And I don't want to change that too...
@pseusys In this case you lose assets optimizations...
@alexander-akait I thought it would be easier to process the assets by extracting them from HTML files with html-loader.
However you're right, if that's not possible I think I should consider replacing <img>
tags with e.g. <a>
tags with background-image
property set via CSS.
I am think thinking you ejs-loader
should support src
/etc resolving and create assets for them not only compile them, anyway you can try:
ejs
as transformer<img src="{%public_path%}/images/image.png">
Or you can even combine these approaches.
Using import something from "./test.html"
usually means you want to use HTML template in runtime
Any progress on this Feature? In webpack 4 I use html-loader and then export HTML into their own .html file.
module: {
rules: [
{
test: /\.(png|svg|jpg)$/,
use: [
{
loader: "file-loader",
options: {
context: "src",
name: "[path][name].[ext]",
},
},
]
},
{
test: /\.html$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].html",
},
},
{
loader: "extract-loader",
},
{
loader: "html-loader",
options: {
minimize: false,
attributes: {
urlFilter: (attribute, value) => !/\.(js|css)$/.test(value),
}
},
},
],
},
],
}
My source HTML is:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="main.css">
</head>
<body>
<img src="./img/3.png" alt="">
<script src="index.js"></script>
</body>
</html>
My entry index.js is:
import ("./index.html")
@GMartigny @mbibko @pseusys
You can try to use the new universal html-bundler-webpack-plugin.
Note:
entry point
is an HTML templateProfit You specify all the source scripts and styles in one right place (in HTML), instead of defining them in many places: defining JS files in Webpack Entry, importing SCSS into a JS file.
For example, there is ./src/views/home/index.html:
<html>
<head>
<!-- load source styles here -->
<link href="./style.scss" rel="stylesheet">
<!-- load source scripts here and/or in body -->
<script src="./main.js" defer="defer"></script>
</head>
<body>
<h1>Hello World!</h1>
<img src="./logo.png">
</body>
</html>
The generated HTML contains the output filenames of the processed source files, while the script and link tags remain in place:
<html>
<head>
<link href="/assets/css/style.05e4dd86.css" rel="stylesheet">
<script src="/assets/js/main.f4b855d8.js" defer="defer"></script>
</head>
<body>
<h1>Hello World!</h1>
<img src="/assets/img/logo.58b43bd8.png">
</body>
</html>
Add the HTML templates in the entry
option (syntax is identical to Webpack entry):
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
module.exports = {
plugins: [
new HtmlBundlerPlugin({
entry: {
// define all your templates here, the syntax is the same as Webpack entry
index: 'src/views/index.html', // => dist/index.html
// 'pages/about': 'src/views/about/index.html', // => dist/pages/about.html
// ...
},
js: {
// output filename of extracted JS from source script loaded in HTML via `<script>` tag
filename: 'assets/js/[name].[contenthash:8].js',
},
css: {
// output filename of extracted CSS from source style loaded in HTML via `<link>` tag
filename: 'assets/css/[name].[contenthash:8].css',
},
}),
],
module: {
rules: [
// styles
{
test: /\.(css|sass|scss)$/,
use: ['css-loader', 'sass-loader'],
},
// images
{
test: /\.(ico|png|jp?g|svg)/,
type: 'asset/resource',
generator: {
filename: 'assets/img/[name].[hash:8][ext][query]',
},
},
],
},
};
That all sounds fantastic.
A common use-case for this loader is to use it to generate an HTML file. Many users use this in tandem with the
extract-loader
. Sadly,extract-loader
is very outdated and seems unmaintained.Feature Proposal
html-loader
should support an option to output the HTML code it create into a new file. It could also output the CSS code, but this is maybe out of scope for this loader.Feature Use Case
Users can use a
.html
as entry. This means that they'll need thehtml-loader
to handle the HTML code. Having an extract option would allow to output the HTML code into a new file in the destination folder, which is convenient for continuous deployment.