Google's hosted dojox.gfx - dojo

I'm using the following html to load dojo from Google's hosting.
<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("dojo", "1.1.1");</script>
<script type="text/javascript">
dojo.require("dojox.gfx");
...
This errors out on the requre line with an error like dojox.gfx is undefined. Is there a way to make this work, or does Google not support the dojox extensions?
Alternatively, is there another common host I can use for standard dojo releases?

Differently from when you reference the .js files directly from the <script> tag (note that google js api also supports this, see here), google.load is not synchronous. This means that when your code reach google.load, it will not wait for dojo to be fully loaded to keep parsing; it will go straight to your dojo.require line, and it will fail there because the dojo object will be undefined.
The solution (if you don't want to use use the direct <script> tag), is to enclose all your code that references dojo in a start function, and set it will as a callback, by doing:
google.load("dojo", "1.1.1", {callback: start});
function start() {
dojo.require("dojox.gfx");
...
}
or
google.setOnLoadCallback(start);
google.load("dojo", "1.1.1");
function start() {
dojo.require("dojox.gfx");
...
}

A better question is - why would you want to? If you are developing on your localhost then just use a relative path, if you're developing on an internet facing server - stick the dojo files on that.
Also - make sure you're not falling foul of the same origin policy

I believe that google becomes the namespace for your imported libraries. Try: google.dojo.require.
Oh! And as pointed out below, don't forget to use google.setOnLoadCallback instead of calling your function directly.

dojox is practically unmaintained, and will be taken out from dojo-2. There are major problems with most widgets in dojox, there is only a few good.
IMHO dojo should be self-hosted, because there are always things what you need to overwrite - for example, you need some fix in this dojox.gfx.

Related

Dynamic publicPath When Rendering Pages with Vue SSR

We're happy users of Vue and its server-side rendering module, Vue SSR. One of the requirements of my project is that we be able to dynamically adjust Webpack's publicPath at runtime, so that we can obtain assets from our different CDNs (we have two, one for test and one for prod).
We are able to accomplish this easily on the client-side using the __webpack_public_path__ free variable, and you can also override the publicPath within the SSR client manifest for asset URLs injected into the <head>.
Yet we continue to have issues with asset URLs that are housed directly within our templates and are rendered by SSR. For example, imagine if we had the following image within our tag:
<img src="~#/test.png" />
Our goal is that, on both the server and the client, we could adjust that URL to be prefixed how we please via publicPath. There doesn't seem to be a way to dynamically update the publicPath once the vue-ssr-server-manifest.json has been generated, the resulting URL ends up being something relative like /static/test.png or whatever we original cited in our Webpack config.
Per our project constraints, it's not possible to rebuild our SSR bundle, so we need to do this at runtime. We've tried adding placeholder values as our publicPath, e.g. __CUSTOM_WEBPACK_PUBLIC_PATH__, and replacing them in the server bundle at runtime, but that ends up being ineffective since publicPath is also embedded in other Webpack generated files.
Wondering if there is a cleaner way to achieve what we need directly via Vue SSR, or if this is something we just can't configure at runtime. Thanks for reading!
Late follow-up here, but we eventually solved this issue.
We found that setting __webpack_public_path__ globally in our Node.js process did result in the correct public path being applied to our assets in our server bundle.
Once that global is present both on the window (e.g. client-side), and globally in the node process (e.g. server-side), things started working as we wanted.
We faced similar type of problems in our webapp as well. BTW, we implemented a CDN plugin for vue.
export const CDNPlugin = {
install(Vue, { CDN, assetsManifest }) {
Vue.prototype.$cdn = {
...CDN,
asset(name) {
return `${CDN.baseUrl}${assetsManifest[name]}`;
},
resource(filepath) {
return `${CDN.baseUrl}/resources/${filepath}`;
}
};
}
};
Install this plugin both of your ssr and csr file.
Vue.use(CDNPlugin, {
CDN: { baseUrl: 'https://my.static.cdn.com' },
assetsManifest: yourAssetManifestObject,
});
And the usage of this CDN plugin inside vue template is as below
<img :src="$cdn.asset('relative/path/to/asset/style.css')">
If you think it is helping a bit, then I can share more regarding our implementation.
I spent an entire day trying to figure this out. In the end I used this:
https://github.com/agoldis/webpack-require-from
Worked like a charm, client side and server. Be aware you need to set a global.MY_BASE_URL in your node/server somewhere AND you need to inject a window.MY_BASE_URL somewhere in your HTML. Then just configure webpack.
plugins.push(new WebpackRequireFrom({variableName: 'MY_BASE_URL'}));
Similar problem occurred in my project, and finally I worked it out.
Ryan's answer really helps, but there is one thing I want to clear up. __webpack_public_path__ is a LOCAL variable in webpack bundled code, which means __webpack_public_path__ and global.__webpack_public_path__ is not the same. You need to do something like
__webpack_public_path__ = process.env.ASSET_PATH;
to specify public path (https://webpack.js.org/guides/public-path/#on-the-fly FYI).
Last, please make sure your process.env.ASSET_PATH is not undefined, maybe you have to set it manually to global in your server code.
global.process.env.ASSET_PATH = process.env.ASSET_PATH;

What's the best way to add JQuery to Enduro.js

I'd like to be able to use Jquery in my Enduro.js project, but there is not a single sample using it on github Enduro.js page
Libraries seem to be loaded in Enduro.js using RequireJS, wth the line found at the bottom of the default index.hbs :
{{!-- <script data-main="/assets/js/main.js" src="/assets/vendor/requirejs/require.js"></script> --}}
and the following code found un "assets/js/main.js" by default in all Enduro.js samples :
require.config({
baseUrl: '/assets/',
paths: {
// 'jquery': 'vendor/jquery/dist/jquery.min',
},
})
require(['jquery'], function ($) {
$(document).ready(function () {
console.log('requirejs ready to use')
})
})
The Jquery "path" line is commented out, and there is no /vendor directory in /assets by default.
Is there an automated way to install jquery in Enduro.js or is it just simply about creating by hand a /vendor folder, and copying /Jquery inside it ?
Well, there are many ways to use JQuery in Enduro. I'm not sure if it is the best way to import it (it could exist better ones).
In my current project, I'm using the CDN for reasons of efficiency. If you have no problem using CDNs I'd recommend it.
just copy this code:
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous">
</script>
And then, paste it just before closing the body tag.
Another way is to create a folder inside /assets/js called 'vendor' and there, you cat put the jquery-3.3.x.min.js (Or whatever version you would like to use). Of course, you have to download it first from the official site.
After doing that, you just have to import it via HTML (before closing body tag):
<script src="assets/js/vendor/jqueryfile.js"></script>
NOTE: Creating the folder called 'vendor' is optional, you just could paste the file inside /assets/js. And make sure you type the right path to import it.
NOTE 2: remember that you should never touch the files inside _generated, so if you paste the file inside _genereated/assets/js, everything is going to work, but when you migrate your site to production or anywhere else the app will crash.
Hope this helps.

How do I use Dojo Toolkit in an Electron application?

I'm exploring Electron and I've run into a roadblock. I can't figure out how to load the Dojo Toolkit and use it in Electron.
For example, here is the simple "Hello World" for Dojo:
<!DOCTYPE html>
<html>
<head>
<title>Tutorial: Hello Dojo!</title>
</head>
<body>
<h1 id="greeting">Hello</h1>
<!-- load Dojo -->
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"
data-dojo-config="async: true"></script>
<script>
require([
'dojo/dom',
'dojo/dom-construct'
], function (dom, domConstruct) {
var greetingNode = dom.byId('greeting');
domConstruct.place('<em> Dojo!</em>', greetingNode);
});
</script>
</body>
</html>
That works fine in a browser, but doesn't work at all in Electron. After a couple hours of googling and trying 50 different experiments I've gotten nowhere.
Can someone please enlighten me?
While you can disable node-integration as Shwany said, I believe that will effectively render the ipc modules useless, which will probably pose undesirable limitations since you won't be able to communicate between the main and renderer processes.
However, it is possible, with a bit of finagling, to get Dojo to play nice with Electron. There are only a couple of things you need to do in your entry page.
Firstly, force the host-node has feature to false. This can be done by setting it in dojoConfig.has, e.g.:
var dojoConfig = {
async: true,
has: {
'host-node': false
}
}
Secondly, as Shwany pointed out, Dojo is going to see the already-existing require, so we need to move that out before loading Dojo:
// Move Electron's require out before loading Dojo
window.electronRequire = require;
delete window.require;
After loading dojo.js, you can move Dojo's require elsewhere and move Electron's back, if you wish. Whether you want to do this may depend on how you intend to code the client side of your application. Ostensibly, Dojo's global require is never needed, since you can request a context-sensitive require in any defined module via the 'require' module ID.
If you want to see a scaffolded Electron application incorporating Dojo, I created a boilerplate a few weeks ago (though be advised it's currently relying on a fork of electron-packager). If you want to see an example of a more full-blown Electron/Dojo application, I wrote a music player called Nukebox a couple of months ago which uses Dojo and dgrid (though its scaffolding is a bit different than the newer boilerplate).
I have your test code working in Electron.
First, I assume you are trying to load dojo.js from the web. //ajax.googleapis... etc will probably attempt to pull the file from the file system. I added http: to the front of it. That allowed me to open a .html file in the browser and work. I am not sure if that was an oversight or not.
Secondly, because the browser-window has node-integration on by default, 'require' is already defined and it does not understand what you are passing to it because it expects a path not an array. If you construct your browser window with node-integration turned off it should work:
app.on('ready', function() {
mainWindow = new BrowserWindow({width: 800, height: 600, "node-integration": false});
mainWindow.loadUrl('file://' + __dirname + '/index.html');
mainWindow.openDevTools();
mainWindow.on('closed', function() {
mainWindow = null;
});
});
Note the "node-integration": false. This may cause additional issues if you want to use node integrations in your app. However, your code should work.

Dojo Builds...? What now?

A while back, I looked into a solution for the "flash of unstyled content" when using Dojo and Dojo themes. Someone suggested to combine everything by creating a build, and it'll reduce the load/parse time and remove the need to use preloader overlays, etc.
However, it seems like Dojo is severely lacking in straightforward, "real world" useage examples and tutorials for a lot of its functionality, this especially. A lot of the resources tell you how to set up a build, but not how to implement it.
Let's say I have this in "pageinit.js":
require([
'dojo/parser',
'dojo/dom',
'dojo/dom-class',
//etc...
'dijit/form/ValidationTextBox',
'dijit/form/CheckBox',
// etc...
// Dom Ready call
'dojo/domReady!']
function(
Parser,
Dom,
Class,
// etc...){
// do stuff with parser, dijits, so on.
}
)
Some of the require calls were removed for brevity, but there's a handful of dom requires, style classes, some dijits, etc. When this page loads, there's the flash of unstyled content and then it's fine.
Using the Dojo Web Builder, I selected the modules I'm using, and ran it. It downloaded a zip with a lot of files under it, including a new dojo.js and custom_layer.js.
So my question is now, how do I use these new combined and minified files in place of my "non-build" version? What do I require? Or do I?
So confused...
First, let's understand how the AMD(require/define) API works.
require([
'dojo/parser',
'dojo/dom',
'dojo/dom-class'
], function(parser, dom, domClass){
});
This is going to call the require function, specifying that I need three modules in order to do some work. require will get each module. If will determine if the module has been loaded. If it hasn't it will asynchronously get the file, and load the module into the javascript runtime. Once require has retrieved all of your required modules, it will execute your callback (the function) passing the modules as arguments to the function.
Next, let's understand the build. The dojo build does exactly what you describe. It will compress a bunch of the individual files into a single file. this will make the page load quicker and prevent that 'flash' that you describe.
Finally, putting it all together, you should include the custom_layer.js file along with the dojo.js file.
<script type="text/javascript" src="path/to/dojo/dojo.js" />
<script type="text/javascript" src="path/to/custom_layer.js" />
The web browser will load these two files and evaluate the code. Instead of lazily loading each module in it's own file, the module will already be loaded because it was defined in the custom_layer.js.
So, the answer to your final question is that you should NOT change any of your code based on the specific version of code (source vs custom build) that you are using. Using the AMD api, it should just work.
Not sure if it's best practice or not, but I was seeing the flash of unstyled content when I first started (a few days ago), and saw several examples somewhere that takes care of by just hiding the <body>. Parse will unhide it when it's ready to show something.
<body style="visibility: hidden;">

Jquery with other libraries

I am getting an error message as element.dispatchEvent is not a function. I am using jQuery with prototype in rails 3 application. In my layout file, I have added the js files as below
javascript_include_tag 'jquery','jquery_ujs','prototype','shadowbox/shadowbox.js'
<script type="text/javascript">jQuery.noConflict();</script>
I have also added jQuery.noConflict as above and used jQuery instead of $ in jQuery functions. Any idea how to resolve this.?
In my another controller page action I have also mentioned the same thing as there are some js files which needs to be reloaded only for that particular page.
I am a newbie in js as well as rails also.
you should use jQuery.noConflict right after src to the jQuery library
Using jQuery.noConflict(); should be enough. Please check the code of the page in your browser so you can see when prototype is actually added.
You should have jQuery, then the .noConflict call, then prototype.
Besides adding the 'no conflict' method, I do this instead (though both would probably be best):
I'll 'preset' my custom script page. Let's say my prediction is that I will use maybe 5 blocks of code in a page - this is how I preset my page:
jQuery(document).ready(function($) {
// use $ in here like normal!
});
jQuery(document).ready(function($) {
});
jQuery(document).ready(function($) {
});
jQuery(document).ready(function($) {
});
etc. etc.
Notice this uses the jQuery object itself to pass as the callback function to the .ready method so you can once again use the $ identifier within the functions. I can rename it so their will never be a conflict, and I can use the $ identifier within the function like I normally would. Hope that helps.