I feel like this should be more straightforward than it is. I need to access all my javascript libraries from the frontend and because I'm integrating it into an old system, I cannot call require("bundle.js");
from the frontend. Everything in the global scope of the bundled files must be accessible from the global scope of the frontend page importing them through the <script>
tag.
So I need to change the old:
<script src="js/jquery.js"></script>
<script src="js/silly.js"></script>
<script>
$(silly()); // Some function in silly.js's global scope
</script>
To the new:
<script src="js/bundle.js"></script>
<script>
$(silly()); // Some function in silly.js's global scope
</script>
expose-loader: This would totally work if I didn't have 100 global variables that I don't want to explicitly tell it to look for.
ProvidePlugin: Only really lets the libraries see the other libraries. I also cannot explicitly write all the globals I need with my current setup (More are added constantly).
So for more clarity, I need my webpack.config.js
to look like one of these options:
// Everything is wrapped in module.exports and other irrelevant things
plugins: [
new StaticLibraryMergerSuperNeatPlugin("js/*.js")
]
// ...
Or:
rules: [
{
test: /\.js$/,
use: [
"neat-merging-cool-loader",
"babel-loader"]
}
]
// ...
Is there an obvious solution I am missing?
Tl;Dr:
How do I make globals from my bundled js files, be exposed to the global scope when imported on a frontend html page via <script src="js/bundle.js"></script>
?
Btw: If anyone is a webpack legend and knows why this is a bad approach, please post below with a brief explanation so I can fix my life.
Here's an example of how I do it in my own site. I'm not sure if it's the only way, or even the best way, but it's clean, simple, and it works for me.
Important side note - Use window["propName"]
when declaring things on the window because when you run webpack -p
it will uglify any non-strings, so if you define it as window.propName
, it can get changed to something like s.c
and the rest of your code does not know what it is. Declaring it with bracket notation as a string will force webpack to keep the name intact so you can access it from anywhere with the same name.
site.ts (can be .js, doesn't matter)
/*************************/
/*** JQUERY + JQUERYUI ***/
/*************************/
/* var declaration for typescript - not needed if not using .ts */
declare var $:JQueryStatic; declare var jQuery:JQueryStatic;
window["$"] = window["jQuery"] = require("jquery");
require("jquery-ui/effects/effect-slide");
require("jquery-ui/widgets/autocomplete");
require("jquery-ui/widgets/button");
require("jquery-ui/widgets/datepicker");
require("jquery-ui/widgets/tooltip");
/*************************/
/* END JQUERY + JQUERYUI */
/*************************/
/***************/
/*** ANGULAR ***/
/***************/
/* var declaration for typescript - not needed if not using .ts */
declare var angular:ng.IAngularStatic;
window["angular"] = require("angular");
require("angular-sanitize");
/***************/
/* END ANGULAR */
/***************/
/************************/
/*** MISC THIRD-PARTY ***/
/************************/
window["moment"] = require("moment");
window["saveAs"] = require("FileSaver").saveAs;
window["JSZip"] = require("jszip");
/************************/
/* END MISC THIRD-PARTY */
/************************/
/* var declaration for typescript - not needed if not using .ts */
declare var globals:Globals;
window["globals"] = require("./globals");
Layout.html (loaded on every page)
.....
<script src="/dist/scripts/site.bundle.js"></script>
.....
webpack.config.js
var path = require('path');
var resolve = path.resolve;
var AssetsPlugin = require('assets-webpack-plugin');
var WebpackCleanupPlugin = require("webpack-cleanup-plugin");
'use strict';
var babelOptions = {
"presets": [
[
"es2015",
{
"modules": false
}
],
"es2016"
]
};
module.exports = [{
cache: true,
context: resolve('Scripts'),
devtool: "source-map",
entry: {
site: './site.ts',
},
output: {
path: path.resolve(__dirname, './dist/scripts'),
filename: '[name].bundle.js',
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: babelOptions
},
{
loader: 'ts-loader'
}
]
}, {
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: babelOptions
}
]
}]
},
plugins: [
new AssetsPlugin({ path: path.resolve(__dirname, './dist/assets') }),
new WebpackCleanupPlugin({})
],
}];