Dojo build 1.7 built packages does not work - javascript

I'm at the beginning of building my project and I get some errors that couldn't realize why they are being occured.
You can see contents of my app.profile.js file below. I execute
"build profile=../../app.profile.js -r" this line from command prompt and I get no error after the process is done. My problem is if I copy the release(built) version of these packages to the place where the unbuilt versions exist, I get too many javascript errors like "Error: multipleDefine". Even if I copy only dojo, dojox and dijit folders, same errors are keep occuring.
When I look the differences between built and unbuilt of two js files, (for example dojo/Deferred) the only difference I realize is this:
//built
define("dojo/Deferred", [
"./_base/lang",
"./promise/CancelError",
"./promise/Promise"
], function(
define([
"./_base/lang",
"./promise/CancelError",
"./promise/Promise"
], function(
So I'm a little bit stucked at the beginning. I want to try using layers to reduce http requests as soon as possible but I need some help about the situation I mentioned. Any help will be greatly appreciated, thanks.
app.profile.js:
var profile = {
basePath: "..",
layerOptimize: "shrinksafe.keepLines",
optimize: "shrinksafe",
releaseDir: "./release",
hasReport: true,
packages: [
{
name: "dojo",
location: "./dojo"
},
{
name: "dijit",
location: "./dijit"
},
{
name: "app",
location: "./app"
},
{
name: "dtk",
location: "./dtk"
},
{
name: "dojox",
location: "./dojox"
}
],
layers: {
"app/layers/core": {
include: [
"dojo/_base/declare",
"dtk/core/ILifeCycle",
"dtk/core/AppConfig",
"dtk/core/TopicContext",
"dtk/core/NavigationContext",
"dojo/require",
"dojo/_base/Deferred",
"dojo/DeferredList",
"dojo/_base/lang"
]
},
"app/layers/appcontext": {
include: [
"dtk/core/AppContext"
],
exclude: [
"app/layers/core"
]
}
}
};

The Dojo builder will add a module identifier to every module definition unless you tell it not to. This can produce the multipleDefine error.
From the builder documentation:
insertAbsMids (default = undefined)
[truthy] Causes the transform to ensure that every AMD define
application includes a module identifier argument.
[falsy] The
transform does nothing to the module identifier argument in define
applications. In particular, a falsy value doe not cause the
transform to remove a module identifier argument that exists in the
source code.
I was having exactly the same problem until I added insertAbsMids:false to my profile.
eg:
var profile = {
basePath: "./",
releaseDir: "release",
action: "release",
layerOptimize: "shrinksafe",
optimize: "shrinksafe",
cssOptimize: "comments",
mini: false,
insertAbsMids: false,
packages: [
{ name: "dijit", location :"dijit" },
{ name: "dojox", location :"dojox" },
{ name: "dojo", location :"dojo" }
]
}

If your problem is with the id that gets created in the AMD module define(id, [deps], factory)..
I was having a similar issue, I had to manually remove all the id's on the compressed files:
//built
define([
"./_base/lang",
"./promise/CancelError",
"./promise/Promise"
], function()
OR, I had to require the module using the id instead.
For example, I was requiring a module:
require(["app/Dialog"])
which was different than the id added.
require(["demo/app/Dialog"])
It was the only way I got it to work. Anyone else knows how to remove the id or reason why we should always have an id? Not sure if this is relavent to your question, but since you showed the differences.

This will build a layer, requiering all modules needed to create the dojox.image.Gallery besides the components mentioned in the discardLayer.
layers: [ {
name: "../dojox/discardLayer.js",
discard: true,
dependencies: [
"dojox.image.Gallery",
"dojox.image.SlideShow",
"dojox.image.ThumbnailPicker"
]
},{
name: "../drops/layer.js",
layerDependencies: [ "../dojox/discardLayer.js" ],
dependencies: [
"dojox.image.Gallery"
]
Try instead of exclude, use the layerDependencies key - i think the exlude looks for app/layers/core from withing your dojo_source tree and not in dojo_release tree.. So at time of build youre excluding an unknown component.
The above sample is something i've used to be able to override the 3 discarded components elsewhere, however it doesnt suit your needs.
You would need to Not set discard for your core layer and instead simply set it as a dependency (which will exclude all dependencies to the layers, which has allready been built).
Then, depending on which version of dojo youre using - you should call dojo.require("layers.core"); dojo.require("layers.appcontext") or require(["layers/core", "layers/appcontext"], function() { }); to assert that those layers are present.
Before using anything from their dependencies, pull in the requirement with another require call, e.g. dojo.require("dijit.form.Button"); new dijit.form.Button({ ... });. The layer will fill the components into a cached hash (dojo.cache) and to make sure theyre declared fully, pull in the requirement.

Related

Failing to resolve dependency for Ext.ux

I am using ExtJS 6.2
I have the following line in my app.json:
"requires": [
"font-awesome",
"ux"
],
I am trying to create a simple text view using LiveSearchGrid.js, so I have the following in my app_name=md_registry folder md_registry/app/view/main/ListTest.js:
Ext.define('md_registry.view.main.ListTest', {
extend: 'Ext.ux.LiveSearchGridPanel',
//xtype: 'row-expander-grid',
//store: 'Patients',
xtype: 'mainlisttest',
requires: [
'md_registry.store.Patients',
'Ext.ux.LiveSearchGridPanel'
],
When I try doing a sencha app build, I get the following compiler error:
Failed to resolve dependency Ext.ux.LiveSearchGridPanel for file md_registry.view.main.ListTest
I have verified that this file exists in the path:
md_registry/ext/packages/ux/classic/src
From everything I've read, specifying the above requires in my app.json should be sufficient, but it's obviously not.
You are right now creating a universal app, but not using the correct folders for your code. You should definitely look into either creating a classic-only app, or a universal app with correct folder structure. If you want to make a universal app, but not now, you can compile only classic.
The solution was completely unobvious:
Had to comment this out from the "builds" profile in app.json:
"modern": {
"toolkit": "modern",
"theme": "theme-triton",
"sass": {
"generated": {
"var": "modern/sass/save.scss",
"src": "modern/sass/save"
}
}
}
I hope this helps someone!

Using grunt to inject your dependencies

Here is my GruntFile
files: {
'../index.html':
[
[
'../node_modules/**/*.min.js',
],
[
'../js/test/test.js',
'../css/main.css'
]
]
}
The issue with this, is that every min.js file inside my node_modules is gonna be injected. However, I would only like to include the main file of each dependencies (which sometimes can be in node_modules//dist/ and sometimes directly at the root of dep.
Is there a way to specify, only include the "main file" of each dep ?
Let me know if it needs clarification
I think I understand what you are saying. If you only want to include a certain file just explicitly state it. I don't know if this was obvious but the * symbol is a catch all.
Example:
files: {
'../index.html':
[
[
'../node_modules/dist/first.min.js',
'../node_modules/dist/js/second.min.js' <-- usually the last one doesn't have a comma.
],
[
'../js/test/test.js',
'../css/main.css'
]
]
}

RequireJS optimize multi-page app using map config

I'm trying to modularize my existing project by breaking out functionality into separate applications that share a lot of common code. It's a Backbone/Marionette app, and everything is working fine in development mode, but I'm having trouble getting optimization to work. I currently have two pages, with 2 main files and 2 application files. The main files both contain requirejs.config blocks which are almost identical, except the second one uses the map config option to map the app module to loginApp. The reason for this is that most of the other modules depend on the app module for some application-wide functionality, including messaging and some global state variables.
main.js:
requirejs.config({
shim: { ... },
paths: { ... }
});
define(['vendor'], function() {
// This loads app.js
require(['app'], function(Application) {
Application.start();
});
});
main-login.js:
requirejs.config({
shim: { ... },
paths: { ... },
map: {
"*": { "app": "loginApp" }
}
});
define(['vendor'], function() {
// This loads loginApp.js because of the mapping above
require(['app'], function(Application) {
Application.start();
});
});
This works great until I optimize. I'm getting an error about a missing file, but having worked with requirejs long enough, I know that really has nothing to do with the problem. :)
From the docs:
Note: when doing builds with map config, the map config needs to be
fed to the optimizer, and the build output must still contain a
requirejs config call that sets up the map config. The optimizer does
not do ID renaming during the build, because some dependency
references in a project could depend on runtime variable state. So the
optimizer does not invalidate the need for a map config after the
build.
My build.js file looks like this:
({
baseUrl: "js",
dir: "build",
mainConfigFile: "js/main.js",
removeCombined: true,
findNestedDependencies: true,
skipDirOptimize: true,
inlineText: true,
useStrict: true,
wrap: true,
keepBuildDir: false,
optimize: "uglify2",
modules: [
{
name: "vendor"
},
{
name: "main",
exclude: ["vendor"]
},
{
name: "main-login",
exclude: ["vendor"],
override: {
mainConfigFile: "js/main-login.js",
map: {
"*": {
"app": "loginApp"
}
}
}
}
]
});
I'd like to avoid having 2 separate build files, if possible, and I'm working on breaking out the requirejs.config block into a single, shared file and having the 2 main files load that and then load the app files (this is similar to how the multipage example works) but I need that map config to work in the optimizer in order for this to work. Any ideas what I'm missing here?
Update
I've split out the config into its own file, config.js, which gets included by the main-* files. In the main-login.js file, I include the map config above the define and everything works in development mode.
require.config({
map: {
"*": {
"app": "loginApp"
}
}
});
define(['module', 'config'], function(module, config) {
...
The build.js file is the same as above, except with the second mainConfigFile removed. Optimization still fails, though. What I think is happening is, since this is a Marionette app, it's common practice to pass the Application object as a dependency to other parts of the app, including views, controllers and models. When I optimize, I run into two different problems. If I leave removeCombined as true, the optimizer will build in the dependencies from the first app, then remove those files, so when it sees them in the second app, it will fail because it can't find the source files anymore. Setting this to false seems reasonable, but the problem is this then gives me the following error:
Error: RangeError: Maximum call stack size exceeded
I can't find any consistent information on this particular error. It might have something to do with the hbs plugin (similar to text but for pre-compiling Handlebars templates) but I'm not positive that's the case. Since there's no stack trace, I'm not sure where to start looking. My gut feeling is it's a circular dependency somewhere, though. So, my updated question is, how should a multi-page Marionette app be decoupled so as to make sharing code (not just 3rd party code, but custom code such as data models and views) possible? Do I need to remove any dependencies on the core Application object? (That would require an awful lot of refactoring.) Since it works just fine in development mode, is there some trick to r.js's config I'm overlooking? I've tried adding app to the exclude lists as well as stubModules but nothing seems to work. I'm thinking of just creating 2 build files and being done with it, but I'd really like to know how to solve this the "right" way.
Your build file can be like this:
({
...
include: [ './config/main.js' ],
pragmasOnSave: {
excludeBuildConfig: true
}
})
You can use pragmasOnSave to tell optimizer to exclude a section in a file in optimized result, so Requirejs config file can be like following code
requirejs.config({
//>>excludeStart('excludeBuildConfig', pragmas.excludeBuildConfig)
shim: { ... },
paths: { ... },
//>>excludeEnd('excludeBuildConfig')
map: {
"*": { "app": "loginApp" }
}
});
The final solution used was to incorporate Grunt into the build workflow. Inside Grunt, I'm dynamically creating task targets to the requirejs task. I refactored my multiple applications to all use the same folder structure, so it was easy to reuse the same build config for each. There's still the minor inconvenience of compiling the vendor file multiple times, but that's a small price to pay.
Here's the function I use to create the config inside my dev task, in case anyone's interested:
var buildRequireTargets = function(appList) {
var requireTargets = {},
buildConfig = {
baseUrl: "<%= sourceDir %>/js",
dir: "<%= buildDir %>/js",
mainConfigFile: "<%= sourceDir %>/js/config.js",
removeCombined: true,
findNestedDependencies: true,
skipDirOptimize: true,
inlineText: true,
useStrict: true,
wrap: true,
keepBuildDir: true,
optimize: "none",
pragmasOnSave: {
excludeHbs: true
}
};
_.each(appList, function (app) {
requireTargets[app] = {
options: _.extend({
map: {
"*": {
"app": app + "/app"
}
},
modules: [
{
name: "vendor"
},
{
name: app + "/main",
exclude: ["vendor"]
}
]
}, buildConfig)
};
});
grunt.config("requirejs", requireTargets);
};

Getting dependencies to load correctly in requirejs (autobahn and whenjs)

I have been stuck on this problem for the past few hours. I'm trying to get autobahnjs and whenjs to be loaded correctly by requirejs.
require.config({
paths: {
angular: '../bower_components/angular/angular',
angularBootstrap: '../bower_components/angular-bootstrap/ui-bootstrap',
bootstrap: '../bower_components/bootstrap/dist/js/bootstrap',
jquery: '../bower_components/jquery/jquery',
chosen: '../bower_components/chosen/chosen.jquery.min',
text: '../bower_components/requirejs-text/text',
autobahn: '../bower_components/autobahnjs/autobahn/autobahn'
},
packages: [
{ name: 'when', location: '../bower_components/when/', main: 'when' }
],
baseUrl: '/bundles/example/app/scripts/',
shim: {
angular : {
exports : 'angular'
},
angularBootstrap: {
deps: ['angular']
},
autobahn: {
deps: ['when']
}
},
priority: [
'angular'
]
});
require
( [
'angular',
'app',
'autobahn',
'angularBootstrap',
'jquery',
'bootstrap',
'chosen',
'controllers/event',
'services/notify'
], function(angular, app) {
// more code here
});
Autobahnjs has a dependency on whenjs. All the files are loaded (and in the correct order). but when is always undefined. I have absolutely no idea what I'm doing wrong. I've tried all sorts of ways to solve it. I also have a bower.json file if this helps anyone replicate the problem. Thanks in advance.
EDIT: Autobahnjs does not currently support AMD. Whenjs, however, does support it.
As you have noticed already, there is an issue for adding requirejs support to AutobahnJS. There is also more embedded stuff inside AutobahnJS bundled for "convenience", mainly parts from cryptojs.
The challenge simply is: how to best serve all users, not matter if and what module loader they use, and if they want convenience (bundled stuff) or prefer to have stuff separate (and manage/load that themselves).
I can't promise, but I try to address it with priority. However, for further discussion, I think the best place would be the GitHub issue.
This has now been implemented in v0.8.0

Reusing/sharing views & models in different projects with Durandal JS

I'm building multiple applications using Durandal JS. All those applications are located on the same server under the same document root and share some common code. For example they all use the same model & view for login.
How can i reuse/share the login model & view in all those applications without just copy & pasting the files to the projects?
I already tried something with the following folder structure:
ProjectsDir/Project1/app/durandal/..
/models/Shell.js, Main.js, ...
/views/Shell.html, Main.html, ...
/main.js
/main-built.js
ProjectsDir/Project2/app/durandal/..
/models/Shell.js, Main.js, ...
/views/Shell.html, Main.html, ...
/main.js
/main-built.js
ProjectsDir/ProjectsBase/app/models/Login.js
/views/Login.html
This way it would be possible to reference the same login model & view in my ProjectsBase from all other projects by setting the correct route to it in the respective shell.js. This route could look something like this:
router.map([
{
url: 'Login',
moduleId: '../../ProjectsBase/app/models/Login',
name:'Login',
visible: true
},
{
url: 'Main',
moduleId: 'models/Main',
name:'Main',
visible: true
}
]);
This works as expected during debugging but building the production version with the durandal optimizer unfortunately doesn't work.
Actually building does work (it produces the main-built.js just fine) but when i launch the site with the production file referenced i get the following error:
Uncaught Error: undefined missing durandal/../../../MPBase/durandal-app/models/Login
I'd really appreciate any ideas on how I could make the built production file work with the setup I described above.
Of course I'm also open for other ideas on how to make models & views reusable/sharable between multiple projects.
Thanks
With some help from Durandals Google Group I found a solution.
It's not possible to use the provided optimizer.exe but it's quite easy to create a custom r.js config which can handle the setup I described in the question:
First of all I ran the optimizer.exe which created a basic config file (app.build.js) that i used as a starting point.
This config file automatically included all necessary files from the project itself (e.g. Project1).
The only things that are missing in this config file are the references to my shared code (the login files from the ProjectsBase directory). Therefore I added them manually along with a new path.
Custom app.build.js (3 changes highlighted with a comment, the rest is how it was built from the optizimer.exe):
{
"name": "durandal/amd/almond-custom",
"inlineText": true,
"stubModules": [
"durandal/amd/text"
],
"paths": {
"text": "durandal/amd/text",
"projectsbase": "../../ProjectsBase/" // New path to folder with shared files
},
"baseUrl": "ProjectsDir\\Project1\\app",
"mainConfigFile": "ProjectsDir\\Project1\\app\\main.js",
"include": [
"main",
"durandal/app",
"durandal/composition",
"durandal/events",
"durandal/http",
"text!durandal/messageBox.html",
"durandal/messageBox",
"durandal/modalDialog",
"durandal/system",
"durandal/viewEngine",
"durandal/viewLocator",
"durandal/viewModel",
"durandal/viewModelBinder",
"durandal/widget",
"durandal/plugins/router",
"durandal/transitions/entrance",
"projectsbase/app/models/Login", // Include for login model
"models/Main",
"models/Shell",
"text!projectsbase/app/views/Login.html", // Include for login view
"text!views/Main.html",
"text!views/Shell.html"
],
"exclude": [],
"keepBuildDir": true,
"optimize": "uglify2",
"out": "ProjectsDir\\Project1\\app\\main-built.js",
"pragmas": {
"build": true
},
"wrap": true,
"insertRequire": [
"main"
]
}
Now I only had to update my Shell.js to use the correct routes to the Login model & view by also adding a path to requirejs and using it correctly when setting the routes:
Add path at the very beginning of Shell.js:
requirejs.config({
paths: {
'projectsbase': '../../ProjectsBase/'
}
});
Set correct routes in activate method of Shell.js:
router.map([
{ url: 'Login', moduleId: 'projectsbase/app/models/Login', name:'Login', visible: true },
{ url: 'Main', moduleId: 'models/Main', name:'Main', visible: true }
]);
Now i can build my main-built.js which bundles & minifies all relevant files by opening the node js command line, browsing to the directory where the r.js config file is and create the build (the main-built.js) with the following command:
node r.js -o app.build.js
This way everything is included correctly when I'm working with the debug files and it's also working with the build main-built.js which also includes my shared files from the ProjectsBase.

Categories

Resources