Dynamically load/import split vendor chunks/bundles via Webpack - javascript

I have a simple sample application that is structured thusly:
/dist
index.html
app.bundle.js
moduleA.bundle.js
moduleB.bundle.js
vendors~app~moduleA~moduleB.bundle.js
[...sourcemaps]
/node_modules
[...]
/src
index.js
moduleA.js
moduleB.js
package.json
webpack.config.js
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Dependency Pulls</title>
</head>
<body>
<script type="text/javascript" src="app.bundle.js"></script>
</body>
</html>
src/index.js
import _ from 'Lodash';
import printA from './moduleA.js';
import printB from './moduleB.js';
function component() {
var element = document.createElement('div');
var btn = document.createElement('button');
element.innerHTML = _.join(['Hello', 'webpack', '4'], ' ');
btn.innerHTML = 'printA. Click me and check the console.';
btn.onclick = printA;
element.appendChild(btn);
btn = document.createelement('button');
btn.innerHTML = 'printB. Click me and check the console.';
btn.onclick = printB;
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
src/moduleA.js
import printB from './moduleB.js';
export default function printA() {
console.log('AAA I get called from moduleA.js!');
}
src/moduleB.js
import _ from 'Lodash';
export default function printB() {
console.log('BBB I get called from moduleB.js!');
}
/webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: {
app: './src/index.js',
moduleA: './src/moduleA.js',
moduleB: './src/moduleB.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
When I pull in app.bundle.js, I expect the vendor bundle to be auto-pulled as well, since it is a dependency for app.js. Currently, this is not happening - the vendor bundle is not loaded. I'm not even seeing an attempt in the network tab.
How do I tell webpack to automatically load dependencies of a bundle?

Webpack bundling/dependency management does not work exactly in that way. You need to manually add a <script> tag to the html for each bundle (entry).
However, you may want to look into using:
html-webpack-plugin:
https://www.npmjs.com/package/html-webpack-plugin
https://webpack.js.org/plugins/html-webpack-plugin
which will automatically inject the bundle references to your html.
html-webpack-template:
https://github.com/jaketrent/html-webpack-template
may also help with additional customization/features.

Related

webpack export JavaScript class and use in HTML

I am using webpack and trying to use a class exported in HTML.
I am getting error when I try to access the class in HTML.
Below is the example code.
// src/app.js
// I have other imports
export class MyClass {
constructor() {
}
foo() {
console.log('In Foo');
}
}
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
libraryTarget: 'var',
library: 'MyClass',
}
};
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<script src="./main.js"></script>
<script type="text/javascript">
const obj = new MyClass();
obj.foo();
</script>
</body>
</html>
I am getting below error:
Uncaught TypeError: MyClass is not a constructor
Also if I have multiple classes, variables and function then how can I export from JavaScript and access from HTML?
For compiling a library with Webpack:
output: {
library: { type: 'umd' }
}

running page specific setup functions while using web pack - "does not provide an export named 'init_home'"

I have a structure like this, with js files i have bundled with web pack. (all simplified for readability)
home.html
main.bundle.js
home.html
<html>
<head>
<script type="module" src="main.bundle.js"></script>
</head>
<body>
</body>
</html>
inside the src js it would look like this
src.js
import {some-imports} from this.js
window.addEventListner("load", ()=>{
# page load code for ALL pages
})
function init_home(){
#home page init code
}
function init_contact(){
#contact page init code
}
export {init_home, init_contact}
how is the prefered way to call these init functions on each page?
I have tied adding this script tag at the bottom of each page with no luck
<script type="module">
import {init_home} from './static/deploy/main.bundle.js'
init_home()
</script>
I keep getting errors like this.
The requested module './static/deploy/main.bundle.js' does not provide an export named 'init_home'
also is it correct that i am trying to import the same js file twice?
webpack.config.js (just incase)
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
module.exports = {
plugins: [
new CleanWebpackPlugin()
],
entry: {
main: path.resolve(__dirname, './js/fire.js'),
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'deploy')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
]
},
}

Webpack + babel, ReferenceError: class is not defined

I am writing my first JS library and wanted to learn to use babel and webpack.
The problem I am having is that the class (entry point?) that I'd like to instantiate in my index.htm file causes the browser to complain that it's "not defined".
This is my webpack config:
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, './src/js/FormrEditor.js'),
output: {
filename: 'formr-editor.js',
path: path.resolve(__dirname, 'dist/js'),
},
devtool: "source-map",
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: '/node_modules/',
query: {
presets: ['#babel/env']
}
}
]
},
};
And the js:
import {Toolbox, ToolboxItem} from "./Toolbox";
export default class FormrEditor{
constructor(element, config){
/** Find the element to use as the container */
if(element instanceof Element)
this.container = element;
else
this.container = document.getElementById(element);
this.container.classList.add("feditor")
this.buildEditorDom();
}
buildEditorDom()
{
let form = document.createElement("div");
form.classList.add("feditor-form");
let toolbox = document.createElement("div");
toolbox.classList.add("feditor-toolbox");
let handle = document.createElement("div");
handle.classList.add("feditor-toolbox-handle");
let testItem = document.createElement("div");
testItem.classList.add("feditor-toolbox-item");
toolbox.appendChild(handle);
toolbox.appendChild(testItem);
this.container.appendChild(form);
this.container.appendChild(toolbox);
this.toolbox = new Toolbox(toolbox);
this.form = form;
}
}
So in the index.htm file I am doing:
<script src="formr-editor.js"></script>
<script>
import FormrEditor from "./formr-editor";
var formr = FormrEditor(document.getElementById('editor'), {});
</script>
And that's when it complains that FormrEditor isn't defined...
A bit more info:
I am serving index.htm out of a "demo" folder, in which I have symlinks to both formr-editor.js (the output of webpack) and the css.
I have also tried var formr = new FormrEditor(document.getElementById('editor'), {}); without the import as per MarcRo and I still get the same error.
I have tried both export and export default on the class and nothing...
There are a few things you might want to check.
You cannot use ES6 imports in the browser like this - actually the import statement is entirely unnecessary.
Your <script src="formr-editor"> seems like it has the wrong path. Your webpacks output is generating a file at dist/js/formr-editor.js. if you want to import the untranspiled src file in your Browser use <script src="src..." type="module"> - make sure the untranspiled file is also accessible.
How are you serving public assets? Is your formr-editor.js file (generated by webpacks) accessible?
You want to call your FormrEditor class with the new keyword.
Note: you can check in your Browsers dev-tools whether your Browser manages to load the respective files!

Webpack 4 - unable to load images with absolute path in src using url-loader

I have been been struggling with an issue with Webpack. I have tried searching everywhere online for a solution but did not manage to solve my problem.
I am building a React application with the following project structure:
package.json
webpack.config.js
src
- images
- components
-- Display
--- Display.js
--- config.js
- Frame
-- Frame.js
index.js
index.html
Here is webpack.config.js:
var path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
publicPath: "/"
},
module: {
rules: [
{ test: /\.(js)$/, use: "babel-loader" },
{
test: /\.(jpg|png|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name].[ext]"
}
}
},
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{ test: /\.json$/, loader: "json-loader" }
]
},
mode: "development",
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html"
})
]
};
config.js provides a variable with the image path to Display.js, which then passes it to Frame.js as a prop. Frame.js renders the image with the provided path.
//config.js
export const imgPath = "/src/images/icon.gif";
//Display.js
import {imgPath} from "./config.js";
<Frame imgSrc={imgPath} />
//Frame.js
<img src={this.props.imgSrc} />
The problem I am facing is that the image icon.gif is not put in-line in the javascript bundle but instead the browser makes a request to fetch the file, which is not the expected behaviour. When I build the application in production mode, the image is not displayed at all.
Could someone please help me get this right? Basically, there are two problems I am facing:
The images are not made inline by the url-loader
The images are not displayed at all in production build.
Thank you!
You have to import the file first. But since your publicPath is set to '/', and your images are emitted into dist, the actual path to the image you need to use is /icon.gif.
1) Import all the possible files (Be sure to use the correct path here)
// includes.js
import './src/images/icon1.gif';
import './src/images/icon2.gif';
import './src/images/icon3.gif';
2) Export the production file path function
//config.js
import './includes.js';
export const imgPathFunc = num => `/icon${num}.gif`;
3) Import it in Display.js
//Display.js
import { imgPath } from "./config.js";
{serverResponse && <Frame imgSrc={imgPath(serverResponse)} />}

Vue loads and renders well, but then stops working

I have an application using Vue and Webpack. I have this configuration from the webpack docs:
webpack.common.js
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: path.resolve(__dirname, 'src/app.js')
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production',
template: 'src/index.html'
})
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
};
webpack.dev.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
})
In the front I have some Vue code that ran when I developed it using webpack-dev-server.
When I run it with that configuration the page loads with the parameters interpolated and the directives rendered (i.e. v-for) and all stops working (except for a setInterval), the ui is not updated, the events does not trigger the handlers, nothing.
index.html
<div id="app" class="container">
<div class="row">
<div class="col">
<div class="jumbotron">
<h1 class="display-4">Title</h1>
<p class="lead">
Lorem ipsum faciebat <i><b>'{{randomWord}}'</b></i>?
</p>
</div>
</div>
</div>
</div>
app.js
import Vue from 'vue';
import {mockedData} from './mocked-data';
import './components/search-bar';
import './components/word-cta';
var app = new Vue({
el: "#app",
data: function(){
const words = ["foo", "bar", "baz", "faz", "boo", "foz", "bor"]
let i = 0
const getRandomWord = function(){
if(i == words.length - 1){
i = 0
} else {
i += 1
}
return words[i]
}
const data = {
randomWord: words[0],
lastWords: mockedData,
result: ""
}
setInterval(function(){
data.randomWord = getRandomWord()
}, 1700)
return data
},
methods: {
onSearch: function(result){
this.result = result;
}
}
})
I have no idea of what is happening... The console does not help. Below is the output:
vue.esm.js:8439 Download the Vue Devtools extension for a better
development experience: https://github.com/vuejs/vue-devtools
vue.esm.js:8449 You are running Vue in development mode. Make sure to
turn on production mode when deploying for production. See more tips
at https://vuejs.org/guide/deployment.html
EDIT:
I just realized that the problem is to import Vue using webpack. If I remove the import Vue from 'vue';
lines that I have on my .js files and put
<script src="https://unpkg.com/vue"></script>
on my index.html, the problem is fixed and JS behaves as expected.
Can someone explain why?
My assumption is that u missed babel-loader in your webpack config file, so "import" syntax cant be recognized by webpack, and also u should change 'vue/dist/vue.esm.js' to 'vue/dist/vue.common.js'.

Categories

Resources