Injecting multiple external javascript files with Webpack - javascript

Let's say I have a few external javascript files (libraries, if you prefer to call them that way). Those files haven't been adapted to any of the "modern" JS functionalities, meaning that I can't import them like I'd do with some of the most common libraries nowadays (lodash, axios, etc...). The files in question have been always used as old-style import-and-use libraries (<script src="foo.js"></script>).
How can I make Webpack pack (concatenate) all those files and inject them in the head of my index.html, right before my actual bundle?

You can download 'foo.js' manually and add it to project repo. Imagine like you have a folder called 'external-libs' and you can simply import foo.js as something like following
import '../../external-libs/foo.js';
This will be enough for Webpack to append the content of foo.js to your final bundle.

Related

Old AngularJS project migration to bundled js + minification with browserify

I have a very old AngularJS project which is quite big. Instead of creating a bundled .js file composed of all the required code, this project is organized in the following way:
All the .js files are directly loaded in index.html with a <script src="path/to/js">
Even the dependencies minified .js files are loaded in the same way, examples:
<script src="bower_components/angular-route/angular-route.min.js"></script>
<script src="bower_components/angular-resource/angular-resource.min.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.min.js"></script>
The code makes vast use of definitions (functions, classes, enums and so on) declared in different .js files without importing them (because they are all available globally). Examples:
// inside one file, PastFuture is not declared here
if (self.pastFuture === PastFuture.FUTURE) {
... // do something
}
// inside another file, it is not exported or anything, it is just defined
const PastFuture = {
PAST: 'PAST',
FUTURE: 'FUTURE'
};
I want to migrate this project into something a bit more "standard". I've removed bower for npm dependencies but now I'm stuck at forcing all these .js files to get bundled together.
The major problem of the code is that once bundled with browserify, all the definitions not imported stops working, for example, PastFuture is not defined unless I import it manually wherever is required.
Is there a way to overcame / solve this problem without adding exports and require in all the files of the project?
I was thinking that if I concatenate all those .js files instead of trying to make them require each other, it would have the safe effect without the need to add exports and imports.. but as a solution, it just sounds like a hack to me and I was searching for something more correct.

How to load a library in JS/TS in the browser?

I have a project consisting of a TypeScript file and an HTML page. Currently, I am loading several libraries that the TypeScript file requires in the HTML Page by including them in tags, i.e. <script src="https://unpkg.com/tabulator-tables#4.9.3/dist/js/tabulator.min.js"></script>.
Since I would like to use the TypeScript code in other web pages without having to copy a bunch of script tags, is there a way I could load the libraries in the TypeScript file instead of in the HTML file? I tried searching it up and saw some options (for example, import and export) but just using import {Tabulator} from 'tabulator-tables'; obviously didn't work, and I'm somewhat lost.
Because you stated that you're not using any bundler, and that you don't want to use a UMD module in a <script> element, you'll need a version of tabulator-tables that is in the ES module format. It looks like the package provides one at https://unpkg.com/tabulator-tables#4.9.3/dist/js/tabulator.es2015.min.js. You can download that file locally to your project and import from it in your script like this:
import Tabulator from './relative/path/to/where/you/saved/tabulator.es2015.min.js';
You'll need to publish that downloaded module alongside your HTML file, JS file, etc. wherever you're serving the web page, and make sure that you set your own script's type attribute to module in the HTML.

how to use webpack to load CDN or external vendor javascript lib in js file, not in html file

I am using react starter kit for client side programming. It uses react and webpack. No index.html or any html to edit, all js files. My question is if I want to load a vendor js lib from cloud, how to do I do that?
It would be easy to do that in a html file. <script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>
However, in js file, it only uses npm installed packages. How can I import the above lib with no html file? I tried import and require, they only work for local files.
update 10/21/15
So far I tried two directions, neither is ideal.
#minheq yes there is a html file sort of for react start kit. It is html.js under src/components/Html. I can put cloud lib and all its dependencies there like this:
<div id="app" dangerouslySetInnerHTML={{__html: this.props.body}} />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>
<script src="/app.js"></script>
<script dangerouslySetInnerHTML={this.trackingCode()} />
</body>
Good news is it works, I don't need do anything else in js file, no import or require. However, now I have two jquery libs loaded in different ways. One in here, the other through npm and webpack. I wonder it will give me trouble later. The react-routing I use give me 'undefined variable' error if I type a none home path in browser window due to the server side loading I guess. So this solution is not very good.
Use webpack externals feature. This is documented as: link. "You can use the externals options for applications too, when you want to import an existing API into the bundle. I.e. you want to use jquery from CDN (separate tag) and still want to require("jquery") in your bundle. Just specify it as external: { externals: { jquery: "jQuery" } }."
However, the documentation I found a few places are all fussy about how to do this exactly. So far I have no idea how to use it to replace <script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script> in html.
externals is not intended to let you do this. It means "don't compile this resource into the final bundle because I will include it myself"
What you need is a script loader implementation such as script.js. I also wrote a simple app to compare different script loader implementations: link.
var $script = require("scriptjs");
$script("//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", function() {
$('body').html('It works!')
});
You can create a script tag in your JS as
$("body").append($("<script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>"))
There is one html file that is definitely being used to serve to users with your js bundle attached. Probably you could attach the script tag into that html file
Use webpack's externals:
externals allows you to specify dependencies for your library that are
not resolved by webpack, but become dependencies of the output. This
means they are imported from the environment during runtime.
I have looked around for a solution and most of all proposals were based on externals, which is not valid in my case.
In this other post, I have posted my solution: https://stackoverflow.com/a/62603539/8650621
In other words, I finished using a separate JS file which is responsible for downloading the desired file into a local directory. Then WebPack scans this directory and bundles the downloaded files together with the application.

How to include a require.js project in an app and minify both

Having two different projects, a framework and an app which uses this framework, I would like to use requirejs optimizer to minify both together.
Files:
/framework/
js/
some.js
other.js
framework.js
/app/
js/
main.js
module.js
I want to create an app.min.js with requirejs optimizer which includes the framework files, and the app files, in the right order.
However, I want the framework to be able to minify itself, so define() and require() calls in the framework are relative to the framework.js file.
The problem is that if I try to optimize my app, it won't find the framework files because the relative paths used in the framework (like define(['./some'], ...)) won't work if I optimize from my app.
How can I do this properly ?
There might be a better way, but you can represent paths as variables
e.g. relative paths in framework can be 'framework/some' and config can define 'framework/' to be '.' in the framework app. and define 'framework/' to be '../framework' in the app's config.

How can i use the RequireJS optimizer to optimize my app to not use RequireJS anymore?

The Answer is below the question:
Maybe I don't understand the whole RequireJS thing fully,
but here is my problem:
I got a set of files like that:
sub
sub1.js
sub2.js
main.js
In all of the files in sub, i use the define() function to define modules. In the main.js, i use the require() function to load all modules. All of this works.
Now when i run the optimizer (r.js) on the main.js, it just takes the content of all files and puts it into one file. Yes, i can then use this optimized file to do the same as what i could do with the multiple files.
All good, no error.
Now my question: In that optimized file, it still uses RequireJS. Can i optimize it to the point, where it doesn't use RequireJS, where it's just the functions put together?
Answer
You can only include RequireJS into your optimized file by setting the include option to "requireLib".
Are you trying to load the file in the script tag w/o using data-main + require.js? OR, are you trying to render the file so that RequireJS is no longer used at all? I suspect it's the latter, which is not possible. If the former, that is achieved by bundling Require in via a build file option: http://youtu.be/m6VNhqKDM4E?t=12m44s
No you cant. The point of the r.js is to compile all your dependencies situated in multiple files into one. So even after compiling the modules are still AMD modules, but now without the need to load them separately. And the modules still need an AMD loader to get work. The only thing you can do after compiling is to use a more lightweight loader loader like Almond

Categories

Resources