Importing old library which imports its modules - javascript

In our company we have a library, that is divided into modules. These modules are in separate files and each of this modules have it's dependencies on other modules. Each module has a definition function, which registers it for other modules to use it later and also it can require other modules in its definition function. The require is similar to angular:
modules.require(['authentication', 'data', 'http'], module => console.log('Here is my module: ', module).
The library has a Synchronizer class, which based on this require in each module, handles importing and providing of the required modules. When a module has not yet been required, it creates a <script> tag, set it's src to the required module file and appends it to the body.
Here is the problem, because if I just import the main file of my library and try to require some module, it appends a <script> tag but the path to the file is not correct, because it is all bundled together by webpack.
Is there a way in webpack, to state, that this folder (folder with the plugin) should remain as is, so that I can then make requests to the individual files in this folder?
I have tried using "import" statement, "require" and also I tried to change the library into npm package, but I am not really allowed to change the library, because it has been tested in this format. So keeping the library as is, would be the best.
For example if I put this library into:
./static/js/mylibrary
then our library can produce for modules.require(['data'], onSuccess) a <script> tag with src like:
./static/js/mylibrary/data.js
Can I setup webpack so that the file stays there? In development? In production?
I am using a project created by vue-cli

As I mentioned in the comment simply putting it to the "public" directory in webpack did the trick for both, development and production. Don't know why I didn't try this before.

Related

Loading specific module from concatenated file using RequireJS

Trying to use the URI.js library in a project, but having trouble with RequireJS. URI's readme indicates that it works with requirejs - which is true when you're using the source - but not when using the minified/concatenated distribution file on its own - as you would in production.
Their build process scoops several libraries into a single .min file, and they all define themselves as modules.
No matter how I require that script, the only argument I receive is the first module in their distribution file (IPv6) which is not what I need.
Is there something trivial I'm missing?
<script>
require.config({
paths: {
urijs: 'dist/URI'
}
});
require(['urijs'], function(URI) {
console.log(URI);
});
</script>
Indeed the minified file cannot be used because it is not correctly built. All the define calls in it are anonymous whereas they should include the module name. If they had, you'd be able to use the minified file.
To get it to work, in the paths configuration, I've put urijs to point to the directory that contains all the individual .js files of the modules, and then I require URI.js as 'urijs/URI'. I let r.js minify it for distribution of my code.
I've installed it with npm but I've just checked with bower and the process should be exactly the same.

Create a module with submodules

I have a small homebrewed framework. I'm using this in several projects and I would like to bring that in a handy format for reusing it.
I would like to organize the code as follows:
Each prototype has its own file
Each file is a require.js module
I would like to combine all files together in one file for shipping.
I have used r.js to combine all files together in one, but how can I load the modules with require(...) from another js-file which is not part of the combined file? Or more detailed, I would like to use the modules from the combined file in another app which has its own modules.
I mean, require.js expects only one module per file and now I have n modules in one file...
What you are describing is what the bundles option is for. Taking an example from the documentation:
bundles: {
'primary': ['main', 'util', 'text', 'text!template.html'],
'secondary': ['text!secondary.html']
}
With this when if you require main from outside the bundle, and main is not yet loaded, then RequireJS will know that it will find the module main in the same place where the module primary is located.

Using Browserify and RequireJS on the same page?

So i've come across an interesting use case where i'm using Browserify to bundle all of my assets together in a project, but a large external (external to the project) module needs to be loaded in when a certain in-app window is accessed. (It's a video player module made up of three scripts that get pulled in asynchronously when required).
At the moment i'm getting all kinds of errors from uncalled object errors if the requireJS module is loaded in before the Browserified app.js file, to cannot find module errors if loaded in after the Browserified code.
Is there anyway i can get Browserify and RequireJS to play nicely on the same page? I'm losing my mind!
TL;DR - use window.require in your browserified script.
Maybe it would still help someone.
I happen to use an 'external' dojo-based library totally based on requireJS-style AMD, which is absolutely un-"browserifyeble" and un-convertable to CommonJS or anything sane. My own code is totally Browserified. It's working OK like this:
Load the AMD loader (which defines the global require function) before the browserified script:
<script src="dojo/dojo.js"></script> <!-- RequireJS/AMD loader, defining a global 'require'-->
<script src="app/main.js"></script> <!-- The Browserify bundle -->
In your own js, call the require function on window object ('cause you'll have a local browserify-require shadowing the global one)
window.require(['dojo/dojo'], function (dojo) { ... });
The 'external' app or library, which calls require on its own to load submodules etc., works just fine 'cause that code is out of browserify context and the global require is not shadowed there.
Maybe if you have some pure nice standard RequireJS modules, you could somehow convert them to be Browserifiable, but in my case that wasn't an option.
There is a tool called browserify-derequire that resolves this issue by renaming browserify's require statmenets to avoid the naming collision.
It can be installed with npm using:
npm install -g browserify-derequire
Use it as a browserify plugin by changin your build command to:
browserify src/*.js -p browserify-derequire > module.js
There is more discussion on this issue at: https://github.com/substack/node-browserify/issues/790
For a gulp friendly solution (similar to what #Cride5 proposed) you can use gulp-derequire plugin.
Basic example from docs:
var derequire = require('gulp-derequire');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
gulp.task('build', function() {
var bundleStream = browserify({entries: './index.js', standalone: 'yourModule'}).bundle();
return bundleStream
.pipe(source('yourModule.js'))
.pipe(derequire())
.pipe(gulp.dest('./build'));
});
Plugin is also based on derequire module so all options are supported.

How to use gulp to build JavaScript bundles?

I want to use gulp to build bundles of JavaScript files.
For example I have the following structure in my project:
/vendor/vendor1/vendor1.js
/vendor/vendor2/vendor2.js
/js/includes/include1.js
/js/includes/include2.js
/js/bundle1.js
/js/bundle2.js
There are vendor includes (1-2), local includes (3-4), and bundle files (5-6).
Vendor includes are just third-party JavaScript libraries installed with bower or composer. They can be CommonJS, AMD or just a plain-old jQuery plugins.
I want to specify dependencies inside of a bundle files like this:
/js/bundle1.js
(function() {
// Vendor includes.
include('vendor1');
include('vendor2');
// Local includes.
include('includes/include1.js');
include('includes/include2.js');
// Some code here.
})();
I want gulp to process this source file and create a final distribution file (bundle) ensuring that all dependencies (includes) are merged together in a single file. So I can include foo.js from my HTML and all dependencies will be available to it.
I want to have a clear and robust system to manage all dependencies inside of a project and build distribution files.
How can I achieve this?
What format should I use for my own scripts (AMD, CommonJS, other)?
How do I specify dependencies in my source bundle files?
How do I build distribution?
Your question is posed as if there's a single answer, but there isn't. The problem you're trying to solve is one that many people have solved in many different ways, and you've identified two of the major options: AMD and CommonJS. There are other ways, but given that you might be new to Javascript dependency management as well as gulp, I'd recommend going with something that's relatively straightforward (even though this subject is inherently not straightforward).
I think the easiest route for you might be:
use CommonJS to express the dependencies
use browserify to resolve them into bundles
in browserify, use the "UMD" method so that you get a single bundle that will work for apps that use either AMD or CommonJS or are not using either of these dependency management systems
The statement in gulp to run browserify as such might look something like:
var browserify = require('gulp-browserify');
gulp.src('bundles/bundle1.js', {read: false})
.pipe(browserify({
'standalone': true
})
.pipe(rename('bundle1Output.js'))
.pipe(gulp.dest('dist'));
That should give you a dist/bundle1Output.js file.
There is a gulp plugin for this:
https://www.npmjs.com/package/gulp-include
It should do what you want, except that in your bundle file instead of this:
(function() {
// Vendor includes.
include('vendor1');
include('vendor2');
// Local includes.
include('includes/include1.js');
include('includes/include2.js');
// Some code here.
})();
You would have to write:
//=require vendor1/**/*.js
//=require vendor2/**/*.js
//=require includes/include1.js
//=require includes/include2.js
// Some code here

How to structure a JavaScript project?

I'm currently working on a big JavaScript project for which we want to define our own API. I'm using RequireJS as my dependency loader and it suits me just fine, allowing me to define modules in their respective file. I do not make use of my own namespace, a module returns an instance, which can be used in other modules, i.e.:
define(
['imported_module'],
function(module){
module.doSomething();
}
)
However as the number of files grows, I'd like to decide how to structure these files in folders. Currently I use the following scheme to name my files:
[projectname].[packagename].[ModuleName]
An example could be stackoverflow.util.HashMap.js. I would like to introduce a project folder, a folder per package and rename the files to the module name, like:
stackoverflow/util/HashMap.js
This structures my code quite neatly into folders, however the filename reflects only the module now. I'd like to define some kind of routing to be able to define how RequireJS should look for files. Example:
The file
stackoverflow/util/stackoverflow.util.HashMap.js
Should be importable by the statement
define(['stackoverflow.util.HashMap'],function(HashMap){});
Has anyone experience with structuring large JavaScript projects and if so, could you share your approach?
You shouldn't specify the routing info on your js file names, those are the namespace and folder paths' jobs. So stackoverflow/util/HashMap.js is just fine. And you can use define("stackoverflow/util/HashMap", ....) to tell the dependency.
If you need to put your modules in a different folders, you can config paths for your loader, see this manual from RequireJS API.
There's no best way for structure your js files. But put the root namespace in a src folder is always a good practice. You can see the dojo source code and YUI source code and use similar ways for your project. They both are large scale Javascript projects.
actually it's better to get js lib routing to load all js using standard interface: "js.yoursite.com/lib-0.2.js" there should be a router (php or other, and able to cache queries). So there you could determine and control whole pathes that you use. Because common jquery plugin should stay at one dir, with jquery, and your own custom plugins not.
And there you control each project by it's own rules:
jquery/
plugins/
jquery.prettyPhoto.js
jquery.min.js
mySuperJS/
stable.0/ -- there your production version for 1.0 branch
module.js
0.1/
module.js
0.2/
module.js
0.3/
module.js
myOtherlib/
stable.0/ -- production version for all 0.* versions
stable.1/ -- production version for all 1.0 versions
0.1/
0.2/
0.3/
0.4/
0.4.1/
0.4.1.18/
We're using such structure around a year and it's the best for us. But sometimes we use more complex solution and separate all modules for libs, plugins, tools, components and apps.

Categories