Webpack to build HTML page based on different HTML files [duplicate] - html

I am using Webpack to compile my scripts and HTML (using html-webpack-plugin). The thing is, I have 5 HTML files that contains the same parts and I want to move these parts to separate .html files and then include these parts in every HTML file. This way, if I will change these smaller HTML files, it will recompile every HTML file to represent these changes.
Webpack does this for .js files by default, but can I use something like that for HTML files?

You can use <%= require('html!./partial.html') %> in your template. Example here: https://github.com/jantimon/html-webpack-plugin/blob/master/examples/custom-template/template.html

Another slightly different solution.
Using html-loader with interpolate option.
https://github.com/webpack-contrib/html-loader#interpolation
{ test: /\.(html)$/,
include: path.join(__dirname, 'src/views'),
use: {
loader: 'html-loader',
options: {
interpolate: true
}
}
}
And then in html pages you can import partials html and javascript variables.
<!-- Importing top <head> section -->
${require('./partials/top.html')}
<title>Home</title>
</head>
<body>
<!-- Importing navbar -->
${require('./partials/nav.html')}
<!-- Importing variable from javascript file -->
<h1>${require('../js/html-variables.js').hello}</h1>
<!-- Importing footer -->
${require('./partials/footer.html')}
</body>
html-variables.js looks like this:
const hello = 'Hello!';
const bye = 'Bye!';
export {hello, bye}
The only downside is that you can't import other variables from HtmlWebpackPlugin like this <%= htmlWebpackPlugin.options.title %> (at least I can't find a way to import them) but for me it's not an issue, just write the title in your html or use a separate javascript file for handle variables.

Check out Partials for HTML Webpack Plugin for something a little more elegant. It lets you set up HTML files and include them similar to what you're looking for simply like:
plugins: [
new HtmlWebpackPlugin(),
new HtmlWebpackPartialsPlugin({
path: './path/to/partials/body.html'
})
]
Also configurable for where it gets added such as head vs body, opening vs closing, and lets you pass in variables.

You can use html-loader and posthtml. Then you can use the posthtml-include plugin.
const postHtml = require('posthtml');
const postHtmlInclude = require('posthtml-include');
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
esModule: false,
preprocessor: async (content, loaderContext) => {
try {
return await postHtml(postHtmlInclude()).process(content)).html;
} catch (error) {
loaderContext.emitError(error);
return content;
}
},
},
},
},

Related

How to display image using address in DB using Vue.js?

I'm trying to display an image saved with Django REST. When saving, the path that is indicated in the database is "user_avatars/user1/avatar1.jpg".
When I upload an object from the database to the frontend (Vue.js 3) using the API, the address is displayed as "http://127.0.0.1:8000/uploads/user_avatars/user1/avatar1.jpg"
Here you can see that I use "/uploads/" as the MEDIA_URL folder in Django. However, trying to display an image from this link does nothing:
<img src="http://127.0.0.1:8000/uploads/user_avatars/user1/avatar1.jpg">
I tried to do it in several ways, and found one working option:
<img src="../../../uploads/user_avatars/user1/avatar1.jpg" />
Surprisingly, if I try to construct the same path using Vue, nothing loads:
<img :src="getAvatarURL" />
There the "getAvatarURL" function simply returns the string above:
getAvatarURL(){
return "../../../uploads/user_avatars/user1/avatar1.jpg"
At the same time, the only working option, where I manually entered the path to the file, apparently uploads it to the front-end server and only then displays it, because as I noticed in chrome devTools, the path to the file changes to this:
<img src="http://127.0.0.1:8080/img/avatar1.0cb5eef6.jpg" />
I absolutely lost in this. I've tried to change vue config file to change folder where to store images, but it also didn't help.
Please, tell me how to use the link provided from the database correctly?
This going to boil down to how you have your build tools set up, and how you are storing your images.
Maybe not store the full path, but a file name, and have the path be something like public/assets/images/ + filename.ext
Here is how I have my setup. I use Webpack to compile:
webpack.config.js
module.exports = {
entry: { ... },
module: {
rules: [
{
test: /\.(png|jpe?g|gif|bmp)$/i,
type: 'asset/resource'
generator: {
filename: './assets/images/[name][ext]
}
}
]
}
}
Then inside my src file i keep my images in a folder called assets/images. which when compile copies them to public/assets/images.
Then inside my Vue files i can import the file
<script lang="ts">
import { defineComponent, ref } from "vue"
import avatar from '#/assets/images/avatar1.png'
export default defineComponent({
name: 'sidebar-user',
setup() {
return { avatar }
}
})
</script>
and return it to template where it looks like this:
<template>
<img :src="avatar" alt="avatar" />
</template>

How to build a list of links to html files in Gulp?

How can you use Gulp to gather in one html file a list of all the pages that are in the directory?
For example, in the build directory I have two files contact.html with title "Contacts" and faq.html with the title "Frequently asked questions", I need to get them and create a ui.html which would be a list of links to files of the form:
Frequently asked questions
Contacts
Well, with the addition of step your design (a connected css file).
Found the gulp-listing module, but it can not be customized, there it is as follows:
gulp.task('scripts', function() {
return gulp.src('./src/*.html')
.pipe(listing('listing.html'))
.pipe(gulp.dest('./src/'));
});
I used two gulp modules for do this.
gulp-filelist - for create file list
gulp-modify-file - for update this file
gulp
.src(['./html/**/*.html'])
.pipe(require('gulp-filelist')('filelist.js', { relative: true }))
.pipe(require('gulp-modify-file')((content) => {
const start = 'var list = '
return `${start}${content}`
}))
.pipe(gulp.dest('js'))
After run gulp, you got in js/filelist.js something like this:
var list = [
"Cancellation/template.html",
"Cancellation/email.html",
]
You can add this script in your html file, and with js display all info.

Stylesheet not loaded because of MIME-type Angular application

I'm Working on a Angular 6.x application where i'm trying to change theme (dynamically).
The CLI compile everything properly but in developer console im getting this error message.
Refused to apply style from
'http://localhost:4200/vendor/theme-light.css' because its MIME type
('text/html') is not a supported stylesheet MIME type, and strict MIME
checking is enabled.
My file structure looks like this, the path is correct
project
|-src
|-vendor
|-theme-light.css
|theme-dark.css
My theme changing code looks this
import { Component, Inject, PLATFORM_ID } from '#angular/core';
import { DOCUMENT, isPlatformBrowser } from '#angular/common';
#Component({
..
..
})
linkRef: HTMLLinkElement;
themes = [
{ name: 'Light', href: '../vendor/theme-light.css' },
{ name: 'Dark', href: '../vendor/theme-dark.css' }
];
constructor(#Inject(DOCUMENT) private document: Document, #Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
let theme = this.themes[0];
try {
const stored = localStorage.getItem('theme');
if (stored) {
theme = JSON.parse(stored);
}
} catch (e) {
}
this.linkRef = this.document.createElement('link');
this.linkRef.rel = 'stylesheet';
this.linkRef.href = theme.href;
this.document.querySelector('head').appendChild(this.linkRef);
}
}
setTheme(theme) {
localStorage.setItem('theme', JSON.stringify(theme));
this.linkRef.href = theme.href;
}
Now, I don't really understand why this happens. Is am i missing something ? Feel free to ask for more details if needed.
Any help will be really appreciated.
Thanks
Looks like the href is wrong.
There is a good answer to a different question exactly like yours:
The usual reason for this error message is that when the browser tries to load that resource, the server returns an HTML page instead, for example if your router catches unknown paths and displays a default page without a 404 error. Of course that means the path does not return the expected CSS file / image / icon / whatever...
The solution is to find the correct path and router configuration so that you get your plain CSS file / image / etc. when accessing that path.
In your case it's the css href.
Finally figured out Im giving the wrong path on my path configuration href: '../vendor/theme-light.css' thats returns http://localhost:4200/vendor/theme-light.css on the browser which is not the correct path.
Solution
themes = [
//added the missing src ( source root)
{ name: 'Light', href: '../src/vendor/theme-light.css' },
{ name: 'Dark', href: '../src/vendor/theme-dark.css' }
];
Thank You for your answers
when you're using a static folder , please make sure to use "/" . Let's say for example assets is our static folder , we want the image folder which is under the assets , so you type this src="image/img1.png" , that's wrong you have to add "/" ,,, so it will be like this src="/image/img1.png"
Found this answer here Proper solution
The issue could be with a CSS library starting with comments. While on dev, We do not minify files and We don't remove comments, this meant that the stylesheet started with some comments, causing it to be seen as something different from css.
Removing the library and putting it into vendor file (which is ALWAYS minified without comments) solved the issue.
you have to change the place of your file css into the directory assets assets/style.css
and then put these path in your file index.html src/index.html
<link rel="stylesheet" type="text/css" href="assets/style.css" />
in addition you have to modify to file angular.json in styles
"styles": [
"src/assets/style.css",
"./node_modules/materialize-css/dist/css/materialize.min.css",
],

How to download a locally stored file in VueJS

I have an upload system and I am trying to supply a sample template for users. I have a template stored locally in a subfolder in assets, I would like to access that in my VueJS component and display a link to it on the page. These are the applicaple parts of the file structure:
├──app
│ └──Components
│ └──Uploader.vue
└──assets
└──files
└──Template_Upload.csv
In Uploader.vue I have this line:
<a v-bind:href="item.loc" download>{{item.title}}</a>
And in the export I have this line
data() {
return {
item: {title: 'Upload Template', loc: require('../../assets/files/Template_Upload.csv')}
}
This method works if I have an image. Upon clicking on the link, it downloads the image. However, if I use a .csv or a .xlsx file, errors are thrown upon opening the page. I've tried using
import fileTemplate from "../../assets/files/FileTemplate.csv";
As well, and using fileTemplate as the loc property. This also works if I use a picture. But I'm not able to bring in a document. Is this a limitation I can't get past or is there a different method I can try?
I've also gone into Visual Studio (in other words, the .csproj file), and set the Template_Upload.csv Build Action setting is set to "Content" and the Copy to Ouput Directory setting is set to "Copy Always".
These are the resources I have primarily used thus far:
How to import and use image in a Vue single file component?
What are the various "Build action" settings in Visual Studio project properties and what do they do?
For anyone which doesnt want to use webpack, I solved this issue:
create a folder called files in public
I moved there the files I wanted to download
and Voila, WORKED.
<a href="/files/book.pdf" download>DOWNLOAD</a>
Thanks OverCoder, the solution was indeed to add a CSV Loader in order that adds the locally stored files to the webpack server. For anyone else using webpack, I added this module to my webpack.config.js file:
{
test: /\.(csv|xlsx|xls)$/,
loader: 'file-loader',
options: {
name: `files/[name].[ext]`
}
}
Then I could reference the file easily like this in my template,
<a href="/files/Template_Upload.csv" download>File Template</a>
or this
<a :href="item.loc" download>File Template</a>
using the same data return as I said. Using the require statement with the loader puts the "required" files into the wwwroot/files folder when the project builds. Thanks again, OverCoder, this saved me a lot of time.
Just an extension to the #Judd's answer. If you don't have a webpack.config.js, you can use the vue.config.js file. (just create it in the root, if it doesn't exist)
vue.config.js
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.(csv|xlsx|xls)$/,
loader: 'file-loader',
options: {
name: `files/[name].[ext]`
}
}
],
},
},
};
This works for me;
<a href="../../assets/files/FileTemplate.csv" download>Download</a>
It behaves nicely even in dialogs.
I was on Laravel, and I follow this tuto to get mine working:
create an FileController, add a download method
public function downloadFile($file){
$path = public_path().'/app/upload-folder/'.$file; // or storage_path() if needed
$header = [
'Content-Type' => 'application/*',
];
return response()->download($path, $file, $header);
}
create an api entry point in api.php
Route::get('download/upload-folder/{file}', 'FileController#downloadFile');
create a method which uses axios
async downloadTemplateFile(file){
axios.get('/download/template/file/'+file, {responseType: 'arraybuffer'}).then(res=>{
let blob = new Blob([res.data], {type:'application/*'})
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = file
link._target = 'blank'
link.click();
})
}
call from vue template
<li>Download the CSV template here</li>
Hope this will helps others ;)
Place the file you want to download in the public folder as it is the root folder of your application.
File Structure Image ->
Image Link
Give the href link as below :
<a :href="'/files/SampleFile.xlsx'" class="btn btn-primary" download>Sample File</a>
You can provide any file in the folder structure. For example : .pdf, .xlsx, .png etc
Please note, give the href as :href with file path as " 'your file path' "
Tested and Working on Vue3
Try this:
Download
Try this way and it is with a button:
<a href="/files/Template_Upload.csv" download>
<button class="btn btn-primary">Download</button>
</a>

Gulp task to merge JSON and Handlebars from partials into HTML

I'm making a simple proof-of-concept website using JSON as a data source and Handlebars for a templating engine, with a view to 'merging' the two things into a static HTML file.
The website will be very modular, so each component will be built using a distinct Handlebars 'partial', which will each consume data from its own JSON file.
The development structure I have so far is like this:
src/
models/
header.json
article.json
footer.json
partials/
header.hbs
article.hbs
footer.hbs
index.hbs
The contents of the index.hbs file is something like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test App</title>
</head>
<body>
{{> header}}
{{> article}}
{{> footer}}
</body>
</html>
The partials are very simple for now. e.g header.hbs contains:
<header>{{header}}</header>
I have the following gulp file gulpfile.js which goes part way to what I want to achieve:
var gulp = require('gulp');
var data = require('gulp-data');
var handlebars = require('gulp-compile-handlebars');
var rename = require('gulp-rename');
gulp.task('default', function () {
var templateData = {
header: 'Welcome'
},
options = {
batch : ['./src/partials']
}
return gulp.src('src/index.hbs')
.pipe(handlebars(templateData, options))
.pipe(rename('index.html'))
.pipe(gulp.dest('dist'));
});
So far, it bundles in my partials together and outputs everything nicely, as HTML, in a file called dist/index.html.
The thing that's missing is the JSON data part. Currently the JSON data being consumed by the partials is defined in the gulp file (the variable templateData) but I want each partial to consume data from the src/models JSON files to provide clear separation. The name of the JSON file will be identical to the name of the .hbs partial it's consumed by.
I'm unclear how to go about this. The gulp-compile-handlebars documentation suggests that using gulp-data will support what I need, but I'm struggling to piece together anything from the gulp-data documentation that works for my specific use-case.
Could anyone please suggest how I could modify my gulp file to accomplish this?
Many thanks.
If I understand the question, you can use gulp-data to return an object from your models .json file and it will be added to your tempateData object.
Use gulp-data to pass a data object to the template based on the
handlebars file being processed. If you pass in template data this
will be extended with the object from gulp-data.
So this worked for me.
gulp.task('default', function () {
var templateData = {
header: 'Welcome'
},
options = {
batch : ['./src/partials']
}
return gulp.src('src/index.hbs')
.pipe(data(function(file) {
return require('./src/models/test.json');
}))
.pipe(handlebars(templateData, options))
.pipe(rename('index.html'))
.pipe(gulp.dest('dist'));
});
And you can modify the path to your .json file to match the name of the src .hbs file.