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.
Related
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.
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.
I am using requirejs as the module loader in my Typescript project. I found out that some modules (js files) are loaded twice and some are loaded three times and this causes problems. What can be the reason? Can it be because the relative paths are different when importing these modules? That's what I'm suspicious of. How can it be solved?
With the help of another answer on SO: https://stackoverflow.com/a/16380692/6305376, I added the following to my data-main file and it worked:
require.config({
baseUrl: './',
}
)
Apparently, Requirejs creates different modules for the same file if it is imported with different relative urls from different modules. So, setting a base url as such forces all the Requirejs modules to have their name relative to the outermost folder, making a one-to-one mapping between the modules and their names. So each module is loaded only once.
I found out that some modules (js files) are loaded twice and some are loaded three times and this causes problems.
Make sure you don't use file extensions. Its a known issue (module x.js is distinct from x)
I have TypeScript with External modules (ES6 modules), that is resolved and compiled by the webpack and ts-loader in es5 bundle.
And also I have separate modules (usually it's file with class), which may extend, patch and add functionality to main bundle, so these separate modules import dependencies from main bundle.
BUT, these separate modules can be created any time and get to the server any anytime (compiled .js --> upload --> server) so main bundle doesn't know anything about them.
How to implement this? Require.ensure unsuitable, forwarding all the dependencies from window very uncomfortable, including for developing.
P.S.: Previously, the problem was solved very simply by Internal modules (global namepsaces) and concatenating files in bundle. Any module(object) was available from the window, so by native lazy loading (ajax script) could extend, patch and add functionality to bundle.
DllPlugin / DllReferencePlugin + NamedModulesPlugin
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