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)
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.
The following question was rewritten, because I have now a working solution, but no answer to the question above.
The repository that shows different scenarios how to use resources packed with webpack is named example-webpack-dynamic-resources. It contains 3 modules:
inline: a solution, but not useful in my context (many resource files)
file: a solution by using the plugin webpack-require-from
public-path: no solution yet, shows how I would like to use __webpack?public_path__.
I think I have read any resource about webpack and publicPath and __webpack_public_path__, but I don't get it to work. I try to dynamically change the path to static resources, but it fails.
Here is my context:
I build a Javascript library that will be used on web pages (HTML, CSS, Javascript).
It provides a lot (>100) static resources to small image files, combined > 500 KB. Only a fraction of it will be used by the user looking at the web site.
Therefore I would like to pack the CSS into the bundle, but keep the image resources in a directory located on the server somewhere. The default path to it will be /img.
As long as I use the same structure (which means, images only under ROOT/img/**, everything is ok.
But the users of the library should be able to configure the path to the image resources on their will.
You will find all relevant files in my example repository example-webpack-dynamic-resources in the module public-path-resources.
webpack.js: Use file-loader for images, which are referenced in CSS files. CSS will be inlined by style-loader and css-loader.
src/public-path.js: Define the global variable with a default (no environment variable).
src/index.js: require first public-path, then the logic.
examples/exam1-root/index.html: Tries to use the assets in the sub directory lib, sets the value therefore to __webpack_public_path__ = '/lib/. Not working.
examples/exam2-different-dirs/index.html: Moves the library to a different dir (not relevant), but uses the originally defined directory pgnv-assets for the assets. Working.
examples/exam3-non-standard-dirs/index.html: Try to use instead my-assets as directory for the assets. Not working.
How could the __webpack_public_path__ defined at runtime in the index.html file?
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.
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
So the situation is the following:
I have a bunch of page specific js files which I'm optimizing using r.js.
99% of them define a a module called core.js as a dependency. Core has 5 dependencies of it's own.
I wanted to leverage caching by excluding core from the optimised versions of the page js files.
So in my build.js I tried something along the lines of:
modules: [
{
name : 'modules/core'
},
{
name: 'homepage',
exclude : ['modules/core']
}
]
When I run the optimiser it optimises both modules/core & homepage just fine.
Going to a page that uses homepage.js the issue is that: core.js & it's dependencies are being loaded in individually, leading to 7 requests instead of 2.
In the above example, what I'm trying to achieve is: have homepage.js and it's dependencies optimised into a single file and have it load in an optimised version of core.js rather then loading in the core.js and it's dependencies separately.
Is that even possible?
You have two options, after a build either:
1) modify the top level loading such that modules/core is loaded before any other loading:
require(['modules/core'], function () {
//Now do normal require stuff in here
});
Use another nested require() call in there for homepage if you see its modules requested before homepage finishes loading.
2) Insert a require.config block that points all the modules in core to the core file. requirejs will only fetch the core.js file once when multiple module IDs all point to it:
require.config({
paths: {
'mod/one': 'modules/core',
'mod/two', 'modules/core',
...
}
});
Or see this kind of example project that sets up loading a common and then a page-specific layer, but works without having to do a source modification after a build (just uses a variation of #1, but sets it up to work in source form):
https://github.com/requirejs/example-multipage