Simple Vue.js with webpack - javascript

I know basically nothing about javascript/webpack/npm/whatever but I am trying a simple Vue.js app.
It looks like this:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue Test</title>
</head>
<body>
<div class="vue-app">
{{ message }}
</div>
<script src="/static/testvue.bundle.js"></script>
</body>
</html>
main.js
import Vue from 'vue';
new Vue({
data: {
message: 'Testing Vue'
},
el: '.vue-app'
});
webpack.config.js
var path = require('path');
module.exports = {
entry: './main.js',
output: {
filename: 'testvue.bundle.js',
path: path.join(__dirname, '')
},
devServer: {
inline: true,
port: 8080
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}
]
}
};
When I go to the webpage, it is blank and I see this in the "elements" in the console:
<!--function (e,n,r,o){return Ce(t,e,n,r,o,!0)}-->
Any idea what's going on and how to make it work? It's like it's trying to do something, but something doesn't line up. I've tried changing a few things that I have seen differently like using #vue-app instead of .vue-app or changing it to be under 'body' and then putting the {{message}} directly into the body but that doesn't help and I dont know what the difference is.

So, looks like the issue is that webpack wants the "ESM" version of Vue.
You can add some stuff to the webpack.config.js as per: https://v2.vuejs.org/v2/guide/installation.html
And then it seems to start working.
Code snippet
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
I am not sure what the difference is or why this matters though.

You need to return message in data.
new Vue({
data() {
return {
message: 'Testing Vue'
}
},
el: '.vue-app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue Test</title>
</head>
<body>
<div class="vue-app">
{{ message }}
</div>
<script src="/static/testvue.bundle.js"></script>
</body>
</html>

Related

Why does embedding webpack into index.html gives me an unexpected token error?

I have tried to add Webpack to my vue project to use the require.context, but unfortunately it doesn't work.
When I run my project I get these errors:
Uncaught SyntaxError: Unexpected token '<'
and
Error in mounted hook:
TypeError: __webpack_require__(...).context is not a function
The "Unexpected token" error comes from embedding Wepback in index.html with the script tag. But when I delete it the error goes away.
Here's the code:
webpack.config.js
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
]
},
plugins: [
new VueLoaderPlugin()
]
};
index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="https://use.typekit.net/hcp1kvq.css">
<title><%= htmlWebpackPlugin.options.title %></title>
<base href="/" />
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="../dist/main.js"></script>
</body>
</html>
Art.vue
<template>
<div>
<h1>Art</h1>
<ArtImage :key="key" v-for="(img, key) in images" :link="imageDir + key.substr(1)" />
<div :key="key" v-for="(img, key) in images" >
<img :src="imageDir + key.substr(1)" class="" >
</div>
</div>
</template>
<script>
import ArtImage from "../components/ArtImage.vue"
export default {
components: {
ArtImage,
},
data() {
return {
imageDir: "../assets", // you know this already just from directory structure
images: {}
}
},
mounted() {
this.importAll(require.context(this.imageDir, true, /\.png$/))
},
methods: {
importAll(r) {
var imgs = {}
r.keys().forEach(key => (imgs[key] = r(key)))
this.images = imgs
}
}
}
</script>
<style>
</style>

HTML Webpack Plugin <script> tag generated twice

If I run yarn run build then the HTMLWebpackPlugin will generate the index.html from a template file, but all my code runs twice because the script tag are added two times.
My index.html template file:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
<%= htmlWebpackPlugin.tags.headTags %>
</head>
<body>
<div id="app"></div>
<%= htmlWebpackPlugin.tags.bodyTags %>
</body>
</html>
My index.html that is generated from HTMLWebpackPlugin:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Website</title>
</head>
<body>
<div id="app"></div>
<script defer src="ecaecb1a919bc0a6e577.main.js"></script>
<script defer src="ecaecb1a919bc0a6e577.main.js"></script>
</body>
</html>
and my webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: '[fullhash].main.js',
path: path.resolve(__dirname, 'dist'),
},
mode: "development",
devServer: {
contentBase: './dist',
port: 9000,
hot: true
},
plugins: [
new HtmlWebpackPlugin({
title: "My Website",
template: path.join(__dirname, "src/webpack_template.html"),
inject: "body",
hash: false
}),
new CleanWebpackPlugin()
],
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env']
}
}
}
]
}
};
So, my target is that one script tag will be at the end of the body.
Thank you very much for your help.
If you add tags to HTML, you must disable automatic injection and inject must be false in this case not "body".
Please check documentation
https://github.com/jantimon/html-webpack-plugin#options
true || 'head' || 'body' || false Inject all assets into the given template or templateContent. When passing 'body' all javascript resources will be placed at the bottom of the body element. 'head' will place the scripts in the head element. Passing true will add it to the head/body depending on the scriptLoading option. Passing false will disable automatic injections. - see the

Html Webpack Plugin renders JS module instead of HTML file

I'm trying to use an EJS loader and the Html Webpack Plugin to compile and output an HTML file but it keeps rendering a file like this:
module.exports = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n </head>\n\n <body>\n <div id=\"root\"></div>\n </body>\n</html>\n"
Here's my webpack config:
module.exports = {
target: 'node',
entry: './src/server.tsx',
output: {
filename: 'server.js'
},
module: {
rules: [
{
test: /\.ejs$/,
use: {
loader: 'ejs-webpack-loader',
options: {
data: { example: 'test' }
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'output.html',
inject: false,
template: path.join(rootDir, '../compiler/templates/index.ejs'),
{ example: 'test' },
minify: false
})
]
}
Here's my 'index.ejs' file:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include ./test.ejs %>
</head>
<body>
<div id="root"></div>
</body>
</html>
And here's my 'test.ejs' file:
<meta charset="UTF-8">
I expect this to output an output.html file that looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="root"></div>
</body>
</html>
But instead I get this:
module.exports = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n </head>\n\n <body>\n <div id=\"root\"></div>\n </body>\n</html>\n"
It looks like the ejs-webpack-loader is working and properly injects the partial, but then the HtmlWebpackPlugin is rendering JS instead of HTML.
How do I get the HtmlWebpackPlugin to render the HTML file properly?
You don't need a special loader (ejs-webpack-loader) in your config, since HtmlWebpackPlugin comes with ejs support out of the box.
Just try to remove it. :]

vue template can't be injected into the related tag

I use webpack to build a simple vue project , here is the three files
index.html
<html>
<head>
<title>Vue Hello World</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
main.js
import Vue from 'vue';
new Vue({
el: '#app',
template: "<p> test <p>"
});
and the webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
entry: './src/main.js',
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader' },
{ test: /\.vue$/, use: 'vue-loader' },
{ test: /\.css$/, use: ['vue-style-loader', 'css-loader']},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
new VueLoaderPlugin(),
]
};
and what show in the browser is
<html>
<head>
<title>Vue Hello World</title>
</head>
<body>
<div id="app"></div>
<script src="main.js"></script>
</body>
</html>
the template doesn't replace the tag, I don't know why. Anyone can help?
Vuejs injects content into #app only on runtime, not on compile-time. Unless you're doing SSR indeed.
Inspect the DOM with devtools inspector because the source-code of the page won't change.

Template in HTML, with Webpack, get error "variable" is not defined

I created template in index.html to generate html-code with js, code below. My Webpack configuration also below. When I run it with webpack-dev-server, I get error: title is not defined. Somehow webpack tries to resolve 'title' by self, instead of delegate it to 'lodash/template'. Please help me fix code, I'm in despair(.
import path from 'path';
import glob from 'glob';
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const inProduction = process.env.mode === 'production';
export default {
entry: {
app: [
'./src/scripts/main.js',
],
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].[chunkhash].js',
},
module: {
rules: [
{
test: /\.s[ac]ss$/,
use: ExtractTextPlugin.extract({
use: ['css-loader', 'sass-loader'],
fallback: 'style-loader',
}),
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: '/node_modules',
},
],
},
plugins: [
new ExtractTextPlugin('[name].[chunkhash].css'),
new webpack.LoaderOptionsPlugin({
minimize: inProduction,
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, './src/index.html'),
}),
],
};
import temp from 'lodash/template'
import data from './data';
const titlePicDiscHalf = temp(document.getElementById('titlePicDiscHalf').innerHTML);
document.write(titlePicDiscHalf({ title: 'Hello World!' }));
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
<script type="text/template" id="titlePicDiscHalf">
<div class="titlePicDiscHalf">
<div class="picture"></div>
<div class="title"><%=title%></div>
<div class="discription"></div>
<div class="buttons"></div>
</div>
</script>
</body>
</html>
The problem is that html-webpack-plugin uses the same template tags <%= %> to insert bundle information into template.
You have two options.
1. Change lodash.template delimiters
You could change delimiters used by client-side lodash/template to something else, so Webpack would ignore it. For example:
_.templateSettings.interpolate = /<\$=([\s\S]+?)\$>/g;
Check out this demo.
_.templateSettings.interpolate = /<\$=([\s\S]+?)\$>/g;
const temp = _.template
const titlePicDiscHalf = temp(document.getElementById('titlePicDiscHalf').innerHTML);
document.write(titlePicDiscHalf({ title: 'Hello World!' }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
<script type="text/template" id="titlePicDiscHalf">
<div class="titlePicDiscHalf">
<div class="picture"></div>
<div class="title">
<$=title$>
</div>
<div class="discription"></div>
<div class="buttons"></div>
</div>
</script>
2. Change html-webpack-plugin delimiters
Install ejs-loader separately and configure html-webpack-plugin to use it to load your template. There you can change delimiters to yours. It could look something like this:
plugins: [
new HtmlWebpackPlugin({
template: './index.html.ejs',
})
],
module: {
rules: [
{ test: /\.ejs$/, loader: 'ejs-loader', query: {
interpolate: /<\$=([\s\S]+?)\$>/g,
evaluate: /<\$([\s\S]+?)\$>/g,
}},
]
},
Now, you can configure your template with two different set of delimiters, one for client bundle lodash template and another for html-webpack-plugin:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title><$= htmlWebpackPlugin.options.title $></title>
</head>
<body>
<script type="text/template" id="titlePicDiscHalf">
<div class="titlePicDiscHalf">
<div class="picture"></div>
<div class="title"><%= title %></div>
<div class="discription"></div>
<div class="buttons"></div>
</div>
</script>
</body>
</html>
Note, <title><$= htmlWebpackPlugin.options.title $></title> is used by webpack, and <div class="title"><%= title %></div> is by client-side lodash.
Just in case someone else falls in the same trap where one simply wants to use a static html file with some <script> inside and subsequently encountering an error like Referenceerror: variable is not defined.
Make sure you are not using JS template strings!
E.g. instead of doing something like
function addLoginStatus(user) {
document.querySelector('.login-status').textContent = `You logged in as user.firstName`;
}
use something like this:
function addLoginStatus(user) {
document.querySelector('.login-status').textContent = 'You logged in as ' + user.firstName;
}
I found that with template strings, the webpack-html-plugin template will naturally try to interpret them, which was not intended in my case.

Categories

Resources