My program is using RequireJS to manage dependencies in javascript, and it works fine - except that I have an issue where the only way to do the minification is to use the r.js optimization system to do minify and combine when I compile the application.
This does work; I have it functioning how I need it to - but it is very wasteful because it puts all of the scripts in a single document. This seems to defeat the entire purpose of the module loading - and it makes the site a great deal slower.
Is there a way - other than manually minifying each file, every time I change them, to have this optimizer keep files separated so that the module loading can still only pull the files it needs?
I am doing the minification/combination using nodejs with a build event in Visual Studio, similar to this;
build.bat
node minify.js -o build.json
build.json
{
"baseUrl" : "../../home",
"name": "../lib/app/config",
"include": [
// each file gets listed here
],
"exclude": [],
"optimize": "none",
"out": "program.js",
"insertRequire": [
"../lib/app/config"
]
}
config.js
require.config({
baseUrl: '/app_content/scripts',
});
Visual Studio Build Event
node "$(ProjectDir)scripts\lib\app\minify.js" -o "$(ProjectDir)scripts\lib\app\build.json"
So this makes a huge program.js file that has everything - with explicitly named modules. It runs and functions, but ... again, that kind of defeats the purpose, right?
it makes the site a great deal slower
That can't be true, concatenating into a single file reduces the amount of necessary HTTP requests for a page and should improve performance quite a bit. If you just want to minify your files, use a tool that does just that - e.g. UglifyJS.
Related
I have the following file structure: ([] are folders)
[MySQL]
ConnectionPool.ts
Connection.ts
MySQL.ts
In my code, I am using typescript to develop the app, which will be built to javascript for the production version. The development version is tested directly from the uncompiled typescript files, using babel with the following configurations:
{
"presets": [
["#babel/preset-env", {
"targets": {
"node": "current"
}
}],
"#babel/preset-typescript"
],
"plugins": [
"#babel/plugin-transform-runtime",
[
"module-resolver",
{
"alias": {
... list of some aliases
}
}
]
]
}
My problem is the following, I do most of my imports like this:
import ConnectionPool from 'MySQL/ConnectionPool`
which works for me, as when I run my dev code, the compiler correctly identifies the file extension to .ts, and it also correctly identifies the built versions file extension to .js.
But if I want to import my MySQL.ts file, I can't do it this way, as I will get the following error: Error: Cannot find module './'. If I specify in my import statement the file extension, everything works correctly, but then, when I build my code, there will be no more .ts files in there, so I will get errors there.
Strangely, on the frontend, where I use webpack, I get no complaints about importing files without extension whose name is the same as a folders name in the same directory. What solutions do I have for this issue, which does not revolve around renaming my files or folders in the structure?
Rename your file MySQL.ts to index.ts and move it into the folder MySQL
In the meantime, I resolved my problem by explicitly specifying .ts as the file extension, and when building the code, using the babel-plugin-transform-rename-import to replace the .ts extensions to .js extension.
I won't accept this as the correct answer, as this is too hacky for me, so if a better solution comes up, I am still open for it.
I don't believe what you want to do is possible, node will automatically include either the file or the directory but if both of them are called the same thing node will have no idea which one to import and it will always prefer one over the other.
Using import Example from 'example' will have node search either for any files called example.js or directories called example with an index.js and it will only load one of them.
The reason webpack does it correctly is because webpack will never bundle a "directory", it will take what you've specified as an import and try all of the resolves extensions until it finds one and then it will import that file, so you'll never have conflicting files with directories with webpack.
I thought maybe a solution is to use aliasing in your typescript config so that you can use import Example from '#example' and differentiate between your directories and files that way. Then you can also do import Example from 'example' if you just want to load the file itself. But even then I don't think that will even work because once it gets compiled to javascript you'll just have the same issue as before with conflicting paths.
That being said, while I understand being a little bit obsessed with naming conventions and small things, I really don't think you should be storing "mysql" outside of the "mysql" directory, for two reasons. The first reason is that it's part of that directory, that's what that directory is for, it contains the "mysql" stuff, so why would you want to store it outside. Secondly using a "index.ts" communicates something to other developers, when I open up a new project or directory I'm immediately looking for something called "index.ts" or similar, otherwise I have no idea where to even begin. Using "index.ts" is a good way to communicate to anyone that "this file right here is the one you're looking for, everything starts here". That being said, just call it index.ts and store it where it belongs.
You can try in your tsconfig.json to set moduleResolution to the classic strategy:
{
"compilerOptions": {
"moduleResolution": "classic"
}
}
Unfortunately, looking at the code, this seems to be impossible in your setup:
import is handled by module-resolver
module-resolver calls the NPM package resolve
resolve.sync checks for the no-extension case before testing extensions.
Given that most systems are going to follow Node module resolution, I think you're out of luck, without some manual aliases or moving files around.
FWIW, NodeJS says that extensions in import are mandatory.
I'm having a problem using Gulp to compile a RequireJS project properly. What I need to do is have gulp create a single distribution file that only includes the file necessary to have the application run.
In our application we are following a modular approach breaking out major pieces of functionality into different repos. So while developing my piece I have RequireJS including angular and many other vendor libraries that are common to all of the projects in the application. However when I go to move my piece into the larger application I no longer need these files in the final output since those dependencies also exist in that application (and having those extra libraries also makes the final distribution file over 300K).
I've tried creating another main.js (called gulp-main.js) file that only includes the dependencies that I need but when I run the gulp process it fails. I don't get an error but it seems to be failing because I'm not including the required dependencies for the project to build successfully. Below is the config object that is being passed to the RequireJS optimize method.
var config = {
baseUrl: 'app/',
mainConfigFile: 'app/main.js',
out: 'dist/app/output.js',
name: 'main'
};
Any ideas on what I could do to either remove the unnecessary vendor files or even split them into a single vendor and a single non-vendor file would really be appreciated. I have already tried using the modules array option but that does not produce the results that I am after since it seems to create a single file for each item defined not a single compiled JS file with all scripts contained within.
Thanks in advance.
When you don't want some file in your final output. add " ! " in Your gulp task's src
example :
gulp.src(['./app/*.js', '!./node_modules/**']) // '!./vendor-libraries-dest to igonore'
What is the difference between exlude and excludeShallow in r.js Why are they used.
The r.js example build file explains the difference between exclude and excludeShallow through examples, where excludeShallow would generally be helpful during development.
//This module entry combines all the dependencies of foo/bar/bip into one file,
//but excludes foo/bar/bop and its dependencies from the built file. If you want
//to exclude a module that is also another module being optimized, it is more
//efficient if you define that module optimization entry before using it
//in an exclude array.
{
name: "foo/bar/bip",
exclude: [
"foo/bar/bop"
]
},
//This module entry shows how to specify a specific module be excluded
//from the built module file. excludeShallow means just exclude that
//specific module, but if that module has nested dependencies that are
//part of the built file, keep them in there. This is useful during
//development when you want to have a fast bundled set of modules, but
//just develop/debug one or two modules at a time.
{
name: "foo/bar/bin",
excludeShallow: [
"foo/bar/bot"
]
},
The r.js documentation further explains that excludeShallow may be useful for rapid development: when using the optimizer through the command line, the excludeShallow option can be used to exclude optimization of a module.
Is there any clean way to load files with other than js extension and not AMD content?
I use the enforceDefine config to make sure my actual AMD code works while developing.
So far I've managed to put together a plugin that sets enforceDefine to false, so I can load 3rd party libraries like so: require(['noamd!handlebars']). That doesn't seem too much hacky to me but I'd like to know if there's a better way.
I'm currently testing the noext plugin and it does its job but also in a kind of a hacky way. I've noticed that it applies the noext parameter twice to the url (test.txt?noext=1&noext=1). I can live with that but optimally I'd like to git rid of all extra parameters. Can that be done?
To load files that aren't JS (such as .handlebars, .mustache) then the text plugin will suit your purposes.
To load normal js files you can use RequireJS as a script loader:
require(['full/path/to/file.js'], function(){
// Fired when file is loaded but if non AMD
// no value will be passed to this function
});
If you would like to treat the non-AMD file as a module, then you can use the shim config to implement it.
you can append a ?MEH=BLAH to the end to stop the .js appending
eg
requirejs.config({
paths: {
"dynamicstripconfig": "../php/domain/config.php?dynamic=1"
}
});
Additionally there a plugin for that as well, but doesn't support paths -> https://github.com/millermedeiros/requirejs-plugins
Added a issue with fix for path support -> https://github.com/millermedeiros/requirejs-plugins/issues/47
If your file isn't actually a dynamic js file then use the text plugin -> https://github.com/millermedeiros/requirejs-plugins
Using Require.js and it works pretty solid.
However, I'm reading about optimization (http://requirejs.org/docs/optimization.html) using r.js.
To my understanding it bundles top-level defined modules into 1 file (great because: less http-calls, minified ) .
This seems fine when I only have 1 pagetype defined, i.e: 1 set of required modules to load. However, in any normal site, you'd have multiple pagetypes each requiring different modules.
Now, I'm just wondering how clever r.js really is? Does it take all the multiple pages (with different 'requires') into account when determining which modules to package together, so that I don't end up with X bundled javascriptf-iles for X pagetypes, even though there's substantial overlap in the modules included in each of these bundled scripts.
Any hints I need to give to the optimizer, is it handled automatically, etc?
Clarification much appreciated,.
What I understand is that the optimizer finds dependencies for a file by looking for require() calls, and makes a list of what it finds. (So it only finds dependencies passed to require() as literal strings.) Then the file is combined with its dependencies (recursively) into one file, and minimized.
You can control what goes into a module in the configuration. Here's a sample:
({
baseUrl: "Website/Scripts",
dir: "Staging/Scripts",
modules: [
{ name: "main", include: ["Rotator"], exclude: ["jwPlayerDialog"] },
{ name: "jwPlayerDialog" }
],
paths: {
"jquery": "empty:"
},
fileExclusionRegExp: /^\.|Microsoft|modernizr|unobtrusive|\.min\.|\.debug\./
})
If you turn off minimization, you can easily see what's being included in each file. A module could be included in more than one file. For example, the Rotator module above will be in main.js, and it will still be available as Rotator.js.