I have a react app and I have generated a bundle.min.js by creating webapack.config.js which looks like the following:
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const glob = require('glob');
module.exports = {
entry: {
"bundle.js": glob.sync("build/static/?(js|css)/main.*.?(js|css)").map(f => path.resolve(__dirname, f)),
},
output: {
filename: "build/static/js/bundle.min.js",
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
plugins: [new UglifyJsPlugin()],
}
I copied the bundle.min.js from the dist\build\static\js folder and included it in the script tag inside my HTML code index.html as shown below:
<html>
<head></head>
<body>
<h1>Bundle Testing</h1>
<p>
Here it comes:
</p>
<script src="bundle.min.js"/>
</body>
</html>
But it doesn't show my app. How should I render my app content inside this HTML code? I'm sure I'm missing something.
Related
I'm using pug as my Node.JS view engine.
And I'm bundling my javascript files using webpack with hashname for cache busting.
The problem here is that I don't know how to include the bundled javascript file name in my pug template because every time it generates a new hash name.
How can I get the hash name generated from webpack and include it in my pug file?
This is how it should include the script file:
doctype html
html
include _head
body
script(src='/_bundle/main.649c4c4e6c8076189257.js')
My webpack.config.js
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
mode: "production",
entry: "./src/_public/js/index.js",
output: {
filename: "main.[contenthash].js",
path: path.resolve(__dirname, "src/_public/_bundle"),
},
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", "css-loader", "sass-loader",
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
filetype: "pug",
}),
new HtmlWebpackPlugin({
filename: "./src/views/base.pug",
}),
],
}
Configure HtmlWebpackPlugin and HtmlWebpackPugPlugin properly:
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const HtmlWebpackPugPlugin = require('html-webpack-pug-plugin');
module.exports = {
mode: "production",
entry: "./src/_public/js/index.js",
output: {
filename: "main.[contenthash].js",
path: path.resolve(__dirname, "src/_public/_bundle"),
},
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", "css-loader", "sass-loader",
],
},
],
},
plugins: [
new HtmlWebpackPugPlugin(),
new HtmlWebpackPlugin({
template: './src/views/base.pug',
filename: 'layout.pug',
}),
],
}
Install npm i HtmlWebpackPugPlugin. You will find the js and css references in the layout.pug file.
Actual solution for 2022.
Install the pug-plugin:
npm i -D pug-plugin
Using the pug-plugin:
the Webpack entry-point is the Pug file
all source scripts (JS/TS) can be loaded via require() in Pug
all source styles (CSS/SCSS) can be loaded via require() in Pug
Webpack config for Pug + JS + SCSS:
const path = require('path');
const PugPlugin = require('pug-plugin');
module.exports = {
output: {
path: path.join(__dirname, 'dist/'),
filename: 'js/[name].[contenthash:8].js' // output hashed filename of JS
},
entry: {
// define Pug files in entry:
index: './src/views/index.pug', // => index.html
about: './src/views/about/index.pug' // => about.html
// ...
},
plugins: [
// enable using Pug files as entry point
new PugPlugin({
extractCss: {
filename: 'css/[name].[contenthash:8].css' // output hashed filename of CSS
},
})
],
module: {
rules: [
{
test: /\.pug$/,
loader: PugPlugin.loader, // the Pug loader
},
{
test: /\.(css|sass|scss)$/,
use: ['css-loader', 'sass-loader']
},
],
},
};
Pug file ./src/views/index.pug:
doctype html
html
head
//- load source styles via require()
link(href=require('./path/to/scss/styles.scss') rel='stylesheet')
body
h1 Hello Pug!
//- load source scripts via require()
script(src=require('./path/to/js/index.js'))
Generated HTML:
<html>
<head>
<link href="/css/styles.f57966f4.css" rel="stylesheet">
</head>
<body>
<h1>Hello Pug!</h1>
<script src="/js/index.b855d8f4.js"></script>
</body>
</html>
I am converting a project to use webpack. But this project has two externally loaded scripts that i do not controll. These scripts require a library I provide via webpack to be global. So I use the expose-loader plugin to accomplish this but it is not working for me.
See project details below:
webpack config:
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
const PATHS = {
src: path.join(__dirname, 'src/'), //absolute path to RepoDir/src
dist: path.join(__dirname, 'dist/') //absolute path to RepoDir/dist
}
module.exports = {
entry: {
main: PATHS.src + 'javascript/app.js'
},
output: {
path: PATHS.dist,
filename: 'bundle.js'
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'src/images', to: 'images' },
{ from: 'src/models', to: 'models' }
]
}),
new webpack.ProvidePlugin({
THREE: 'three',
})
],
module: {
rules: [
{
test: require.resolve('three'),
loader: 'expose-loader',
options: {
exposes: 'THREE',
},
},
]
}
}
My index.html file:
<!-- 8th wall AR cdn scripts. -->
<!-- THESE two scripts below require THREE to be global (window.THREE) -->
<script src="https://cdn.8thwall.com/web/xrextras/xrextras.js"></script>
<script async src="https://apps.8thwall.com/xrweb?appKey=PRIVATEKEY"></script>
<script src="dist/bundle.js"></script>
App.js the entry file:
import THREE from 'three'
import { ARManager } from './modules/arManager';
const manager = new ARManager();
manager.startExperience('X1');
Just to make sure this is the error i am getting:
window.THREE does not exist but is required by xxx
If more context or information is needed please let me know so i can clarify.
I am a complete newb to webpack so all help and suggestions are much appreciated!
So, what I'm trying to do is, generate a html file called index.html based on template.html, that have styling based on style.css and a function handleClick that declared in index.js. The code below works for the styling, but the handleClick is not working. Is this possbile?
This is my webpack.config.js
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
'page': './src/index.js'
},
output: {
path: path.join(__dirname, '/dist'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
'babel-loader'
]
},
{
test: /\.css$/,
use: [
"style-loader",
"css-loader"
]
}
]
},
plugins: [
new HTMLWebpackPlugin({
filename: 'index.html',
template: './src/template.html'
})
]
}
this is my index.js
require('./style.css');
function handleClick(){
alert("called from index")
}
this is my template.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Page's Title</title>
</head>
<body>
<div>This background should be blue</div>
<button onclick="handleClick()"> click me </button>
</body>
</html>
and this is my style.css
div {
background-color:blue;
}
The better way is to add addEventListener to that element using your js file. You can do it like this:
<button id="buttonWithFunction"> click me </button>
<script>
// pure js
document.getElementById('buttonWithFunction').addEventListener('click', handleClick);
//with jquery loaded
$('#buttonWithFunction').on('click',function() {
handleClick();
})
You may need to wrap the following in a document.onload for that to work.
Suggest to check namespace of index.js - as i expect, webpack will wrap it in a namespace.
Try to define function on a window namespace.
window.handleClick = () => console.log('Clicked');
I have started experimenting with webpack and webcomponents. So far I managed only to run this basic web component example without webpack. If I simply load the web component in the index.html using a <script> tag than I get it's content rendered. However, when I try to run the same example using a basic webpack setup I don't see the rendered template.
The server is launched successfully and I can see the console init message. What is the missing step? I would expect to be able to concatenate them this way.
I have the following files:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<meta charset="UTF-8">
<title>Web Components App</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<vs-app></vs-app>
</body>
</html>
main.ts
module.hot && module.hot.accept();
// Components
import { App } from './app';
// Styles
require('./shared/scss/main.scss');
console.log('Initialise Main');
app.ts
/**
* App
*/
export class App extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = this.template;
}
get template() {
return `
<div>This is a div</div>
`;
}
}
window.customElements.define('vs-app', App);
webpack-common.js
const webpack = require("webpack"),
path = require("path"),
CopyWebpackPlugin = require('copy-webpack-plugin'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
// Constants
const BUILD_DIR = path.join(__dirname, "../../build"),
PUBLIC_DIR = path.join(__dirname, "../../public"),
NODE_MODULES_DIR = path.join(__dirname, "../../node_modules");
// Shared between prod and dev
module.exports = {
entry: "./public/main.ts",
output: {
// Since webpack-dev-middleware handles the files in memory, path property is used only in production.
path: BUILD_DIR,
publicPath: "/",
filename: "bundle.js"
},
resolve: {
extensions: ["*", ".ts", ".js"]
},
module: {
loaders: [{
test: /\.ts?$/,
loader: "awesome-typescript-loader",
include: PUBLIC_DIR,
exclude: /node_modules/
},
{
test: /\.css$/,
exclude: /node_modules/,
loader: "style-loader!css-loader!autoprefixer-loader"
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
},
]
},
// Base plugins
plugins: [
new CopyWebpackPlugin([
{
from: `public/shared/images`,
to: 'images'
},
]),
new HtmlWebpackPlugin({
template: 'public/index.html'
}),
// Load bundle.js after libs are loaded
new ScriptExtHtmlWebpackPlugin({
defaultAttribute: 'defer'
})
],
stats: {
colors: true,
modules: true,
reasons: true,
errorDetails: true
}
};
Edit
Eventually I got the component rendered moving the following line window.customElements.define('vs-app', App); from app.ts to main.ts. In the mean time I discovered that even that is not necessary.
// This is enough to trigger rendering
import { App } from './app';
App;
However, I still have an issue. Because of webpack hot reload, the component ends up registered twice, giving an error. Still looking for a fix.
Edit 2
After some research online I managed to find the problem: I did not have the inject: false property. This triggered webpack to load twice the same stuff. Looks like I can finally move forward with developing the app. However I would love to find out alternative ways to this setup, just to get confirmation that I'm on the right road.
new HtmlWebpackPlugin({
template: 'public/index.html',
inject: false
}),
Begin work with webpack and stack. My generated html file consist string with event onclick. But my html file doest't see function in generated file bundle.js. Bundle js file conected successfully(console.log works). But if i write <script>function bar()...</script> in html, onclick work. Help.
Try connect file in head, beggining body, end of body/file - doesn't see function. Bundle.js generated from main.js:
require("path to css...");
function bar(){...};
String in html:
<div class="foo" onclick="bar()">...</div>
Bundle.js:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: "dist",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
options: { presets: ["es2015"] }
,
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style','css')
},
{
test: /\.jade$/,
loader: "jade"
}]
},
plugins: [
new ExtractTextPlugin("main.css"),
new HtmlWebpackPlugin({
template: './src/jade/index.jade'
})
]
};
That's because you don't export your function. One of the main benefits of WebPack is that functions aren't put on global scope by default. Add export default to your declaration:
export default function bar(){...};
With webpack, you must explicitly put names in the global namespace. There are probably many ways to do this, but the easiest is to use the browser's window object:
window.bar = function(){...};
or
function bar(){...};
window.bar = bar;