How to make one bundle from several scripts using webpack? I'm trying to point several entries, but include just last, other just not seen how functions.
That's my app1:
function setCats() {
alert('cat');
}
exports.setCats = setCats;
My app2:
function setDogs() {
alert('dog');
}
exports.setDogs = setDogs;
My index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="bin/app.bundle.js" charset="utf-8"></script>
</head>
<body>
<script>app.setCats()</script>
<script>app.setDogs()</script>
</body>
</html>
My webpack.config.js:
module.exports = {
entry: {
app: [
'./src/app1.js',
'./src/app2.js',
]
},
output: {
path: './bin',
filename: 'app.bundle.js',
library: 'app'
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}]
},
};
After building and running in browser alerted just dog and in console I have this mistake:
index.html:8 Uncaught TypeError: app.setCats is not a function
Thanks :)
It's simple, you can only load one entry point in one webpack output bundle. If you use multiple, they are all loaded but only the last entry point is exported. This is often used to load polyfills before libraries, for example, since they don't export anything anyway.
To do what you want to do, you should simply make another higher-level file where you do this:
var setCats = require('./app1.js').setCats;
var setDogs = require('./app2.js').setDogs;
module.exports = {
setCats: setCats,
setDogs: setDogs,
};
Then simply use only that file as a single entry point (entry: './src/app.js'). After building it the bundled library will work and contain app.setCats and app.setDogs.
Related
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']
}
}
},
]
},
}
I have to migrate old, plain HTML with plain JS files to webpack but I have troubles when I have a variable declared outside functions and used between multiple functions below them.
One of the example:
// import stuff
var recorder;
var blobs = [];
function recordStart() {
recorder = new MediaRecorder(...);
blobs = []
recorder.ondataavailable = (event) => {
console.log("recording");
if (event.data) blobs.push(event.data);
};
recorder.onstop = function(){...};
recorder.start();
}
function recordEnd() {
recorder.stop();
}
$('#capture_button').on('touchstart mousedown', function() {
recordStart();
})
$('#capture_button').on('touchend mouseup', function() {
recordEnd();
})
However, everytime recordEnd is called, JS console always throw undefined error on recorder object, as if the variable never even touched at all by the recordStart function.
Is there something that I do wrong here? I just learn webpack for a week so please bear with me if this is a rookie mistake.
PS. jQuery runs fine, if I run console.log() in them they would fire properly.
Edit: I forgot to mention this issue happens only after I run npx webpack on it with this configuration:
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
minimize: false,
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif|glb|gltf|usdz)$/i,
type: 'asset/resource',
}
]
},
plugins: [
new CopyPlugin({
patterns: [
{from: "src/images", to: "images"},
{from: "src/maps", to: "maps"},
{from: "src/models", to: "models"}
]
})
]
};
It runs well before I migrate to webpack, but after I bundled with it and include the dist/bundle.js in the HTML in dist/index.html the undefined error happens.
<!DOCTYPE html>
<html lang="en">
<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">
<title>Webpack Title</title>
<script src="./bundle.js"></script>
</head>
<body>
...
</body>
</html>
One of the main selling points of modules is to give your code an explicit dependency chain, and to avoid global variables. For variables that you want to be able to access in other modules, you should export them, and import them where they're needed.
export let recorder;
// do stuff
// assign to recorder
and in the other module
import { recorder } from './theFirstModule';
function recordEnd() {
recorder.stop();
}
The other (bad) option is to make recorder explicitly global, so it'll be accessible anywhere - but that defeats the purpose of using modules and makes code harder to reason about, so I wouldn't recommend it.
Instead of doing
var recorder;
, instead, wherever you assign to recorder, assign to window.recorder. (But if I were you I'd really try working within the module system first)
I'm starting using webpack (version 3) and when I try to use jQuery from my "app.js" file then nothing happens:
I npm install --save jquery and:
import $ from 'jquery'
$('body').css('backgroundColor', '#DD0000')
document.body.style.backgroundColor = "red";
And when I try changing the css using document.body.style.backgroundColor = "red";
it tells me "cannot read property style of null"
But for the rest it's working, I mean I tried this successfully :
import json from "./test"
console.log(json)
Here is my HTML head part:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack</title>
<link rel="stylesheet" href="./styles.css">
<script src="./dist/bundle.js"></script>
</head>
Here is my webpack config :
const path = require("path");
const uglify = require("uglifyjs-webpack-plugin");
module.exports = {
watch: true,
entry: './app.js',
output: {
path: path.resolve('./dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: ["babel-loader"],
}
]
},
plugins: [
new uglify(),
]
}
Do you know what I'm doing wrong?
You inserted your script in the <head> section. And since JS is blocking, it's executed right there, before the <body> is parsed and exists (so it's null).
If you want this to work, either put your script at the end of the document, right before the closing </body> tag, or wait for the document to be loaded:
window.addEventListener('DOMContentLoaded', function() {
// Here, you can use document.body
});
or, in jQuery syntax:
$(function() {
// Here, you can use document.body
});
So I created a javascript library using the following starter project https://github.com/a-tarasyuk/webpack-typescript-babel, which uses webpack, typescript and babel.
I change the webpack config to generate a library using UMD so I can use the library in the browser and server.
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, 'src'),
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'lib'),
library: 'mylib',
libraryTarget: 'umd',
globalObject: `(typeof self !== 'undefined' ? self : this)`,
umdNamedDefine: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json']
},
module: {
rules: [{ test: /\.(ts|js)x?$/, loader: 'babel-loader', exclude: /node_modules/ }],
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
new CleanWebpackPlugin()
]
};
Then when I build the library, I have the index.js file in the lib directory
When I drop the index.js in a simple html. how can I use the Value class in the project? I tried the following but it throws a Uncaught ReferenceError: Value is not defined
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="index.js">
</script>
<script>
var val = new Value();
</script>
</body>
</html>
Thanks
I found a solution but I'm not sure if that is the expected behavior. When I inspected the window object the following code works
<script>
var p = new window.mylib.Value();
p.setValue(1000);
console.log(p.getValue());
</script>
So I guess webpack is adding the library to the window object when running in the browser ?
UPDATE:
I think it's because of the globalObject is set to 'this' which will mount the library to the window when in browser.
Currently we're using Webpack for our Module loader, and Gulp for everything else (sass -> css, and the dev/production build process)
I want to wrap the webpack stuff into gulp, so all I have to do is type gulp and it starts, watches and runs webpack and the rest of what our gulp is setup to do.
So I found webpack-stream and implemented it.
gulp.task('webpack', function() {
return gulp.src('entry.js')
.pipe(webpack({
watch: true,
module: {
loaders: [
{ test: /\.css$/, loader: 'style!css' },
],
},
}))
.pipe(gulp.dest('dist/bundle.js'));
});
The problem is that it generates a random character name for the .js file, how are we suppose to use that in our app?
From the github repo:
The above will compile src/entry.js into assets with webpack into dist/ with the output filename of [hash].js (webpack generated hash of the build).
How do you rename these files? Also the new gulp task generates a new file everytime I save an edit:
I can't use c2212af8f732662acc64.js I need it to be named bundle.js or something else normal.
Our Webpack config:
var webpack = require('webpack');
var PROD = JSON.parse(process.env.PROD_DEV || '0');
// http://stackoverflow.com/questions/25956937/how-to-build-minified-and-uncompressed-bundle-with-webpack
module.exports = {
entry: "./entry.js",
devtool: "source-map",
output: {
devtoolLineToLine: true,
sourceMapFilename: "app/assets/js/bundle.js.map",
pathinfo: true,
path: __dirname,
filename: PROD ? "app/assets/js/bundle.min.js" : "app/assets/js/bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
},
plugins: PROD ? [
new webpack.optimize.UglifyJsPlugin({minimize: true})
] : []
};
There was a comment to Leon Gaban's answer as to what his webpack.config.js looked like. Rather than answer that within a comment, I'm providing it here so it formats better.
Per the docs for webpack-stream, "You can pass webpack options in with the first argument"...
So, I did the following to force webpack to use the same output name each time (for me, I used bundle.js):
gulp.task('webpack', ['babelify'],
() => {
return gulp.src('Scripts/index-app.js')
.pipe(webpack({output: {filename: 'bundle.js'} }))
.pipe(debug({ title: 'webpack:' }))
.pipe(gulp.dest('Scripts/'));
});
The key being the options inside webpack(), which are:
{output: {filename: 'bundle.js'} }
As recommended in docs you should use the vinyl-named package on the pipe before webpack-stream. This way you can use a more cleaner Webpack configuration. The following is the task definition i use myself:
'use strict';
const gulp = require('gulp'),
named = require('vinyl-named'),
webpack = require('webpack-stream');
gulp.task('webpack', function () {
gulp.src(['./src/vendor.js', './src/bootstrap.js', './src/**/*.spec.js'])
.pipe(named())
.pipe(webpack({
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015', 'angular2']
}
}
]
}
}))
.pipe(gulp.dest('./build'))
});
The only problem i'm facing with this task definition is that the subfolder are loosed. For example ./src/components/application.spec.js will produce ./build/application.spec.js instead of ./build/components/application.spec.js.
Ah I read on a bit further and figured it out:
gulp.task('webpack', function() {
return gulp.src('entry.js')
.pipe(webpack( require('./webpack.config.js') ))
.pipe(gulp.dest('app/assets/js'));
});
^ here I can just pass in my actual webpack.config and it will use the paths I have already set in there. In my case I just removed app/assets/js since I have that path in now gulp instead.
Still no earthly idea though, why with the first task I created, it generates random hash filenames?
Rather than giving your javascript a fixed filename, a better solution would be to use gulp-inject and insert the generated hash filename into a script tag. This means you don't have to worry about cache expiry on the compiled javascript (which is why the hash filename is being used in the first place).
const inject = require('gulp-inject');
gulp.task('webpack', function() {
const index = './src/index.html';
const scripts = gulp.src('entry.js')
.pipe(webpack( require('./webpack.config.js') ))
.pipe(gulp.dest('dist/js'));
return target
.pipe(inject(scripts))
.pipe(gulp.dest('dist/'));
});
and of course you need the inject section in your src/index.html:
<!DOCTYPE html>
<html>
<head>
<title>index page</title>
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>