Old AngularJS project migration to bundled js + minification with browserify - javascript

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.

Related

Should the 'type="module"' declaration be removed from an html <script> tag after the associated Firebase source has been bundled?

A javascript file containing import statements referencing Firebase browser modules embedded in an HTML file needs to be declared as type="module". But after conversion to ES6 modules, this qualifier seems to be optional.
Is a "bundled" javascript file no longer regarded as a module? It certainly still behaves like a module, at least in the sense that a Javascript function in your bundled file remains unavailable to the DOM (eg, an "onclick" reference to a bundled function won't work).
Examples of tags in Google documents seem to confirm the pattern - scripts using browser modules should be declared type="module", bundled scripts should be left unqualified. But what exactly is going on here?
Advice would be much appreciated
Yes, before you build an app, i.e. before you do npm run build, remove type="module" from all the script tags.
What happens under the hood is that the bundler puts all the code from your .js files into one big file.
You can find that file inside you dist folder.
If you're using Webpack or Parcel or any other bundler, they convert JS from ES6+ to ES5, and ES5 does not support import statements, that is why it puts all the js code into one big file.

Injecting multiple external javascript files with Webpack

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.

Gradual refactoring of Javascript/Jquery file into ES6 modules

I am refactoring a extremely large javascript file into multiple files with es6 modules / webpack. To start with, I am moving a single function out of giantFile.js into singleFunction.js, and then importing this new function file into index.js, which is the entry point for webpack to create bundle.js, which is then included in my template.html file as a script tag. In my template file, I also include giantFile.js as a script tag, which calls the function in singleFunction.js.
Is it simply a case of getting the script's imported in the correct order, or am i mistaken in my understanding of how giantFile.js can access the newly created modules.
Currently, within the console, when I type singleFunction(), i receive 'is not defined' error message', and so it would be good to check my understanding is correct of how I can use modules before further debugging. If anyone can point me towards some good resources on refactoring front end javascript and best practives that would be much appreciated too. Many thanks.
in singleFunction.js
`export default function singleFunction() {...}`
in index.js
import singleFunction from './components/singleFunction'
in template.html
<script src="/frontendHotness/components/singleFunction.js"></script>
<script src="/unstructuredMess/js/giantFile.js"></script>
The webpack compiled version of your giantFile.js should still be your application's entry point and the only file that is embedded in your HTML file using the <script> tag.
During your refactoring, you should gradually move well-encapsulated bits of functionality into separate files, or modules. Those modules export the functionality, to be used by dependent modules.
Your parent module, in this case giantFile.js can now import the different modules it depends on. These dependencies will be resolved by webpack, which moves your parent module together with all its dependencies into one JavaScript file that you can load from your HTML page.
Note that this dependency tree can be arbitrarily deep - your submodules can itself depend on other modules. You should however ensure that your modules encapsulate the functionality to do one particular job while being loosely coupled with other modules. Also avoid circular dependencies.

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 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