I have created an application which has its own set of dojo widgets. I have created a custom dojo build to pack all my library in a single dojo file.
The file has a mix of AMD and non-AMD classes. In fact just one AMD class. I am using dojo 1.7.4 for building although the runtime server is using 1.7.2. I have parseOnLoad=false. This is a must for my WebSphere Portal runtime.
The library has a set of declare, define, provide ... something like:
require({cache:{
'com/gnf/class1':function(){
// wrapped by build app
define("com/gnf/class1", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
dojo.provide("com.gnf.class1");
dojo.declare("com.gnf.class1", null, {
});
(function(){
if( com.gnf.class1.instance == undefined ){
com.gnf.class1.instance = new com.gnf.class1();
}
})();
});
},
'com/gnf/class2':function(){
// wrapped by build app
define("com/gnf/class2", ["dijit","dojo","dojox","dojo/require!com/ibm/btt/util/I18nUtil,com/ibm/btt/util/StringUtil"], function(dijit,dojo,dojox){
dojo.provide("com.gnf.dijit.class2");
dojo.require("com.gnf.util.class3");
dojo.require("com.gnf.util.class4");
dojo.declare("com.gnf.dijit.class2", null,{
}
...
}});
define("com/gnf/app/app", [], 1);
I then include this generated js file in my JSP page using
<script type="..." src="/js/app.js"> </script>
The file is loaded and I can see by using Firebug that the code is executed stoping in each declaration. But, no innner code is executed.
In the end, my set of classes is not available and I receive "class not found" error messages.
Any ideas? How should I load my library? Is there something missing?
Thanks in advance.
Related
I have a component library I am creating with Storybook that needs access to .glb/.gltf files. Based on research, it seemed like the best thing to do here was to use the file-loader Webpack functionality, and augment the storybook main.js as such:
// .storybook/main.js
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials",
"#storybook/preset-create-react-app"
],
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.(glb|gltf)$/,
use: ['file-loader'],
include: path.resolve(__dirname, '../'),
});
return config;
},
};
Then, in my jsx file that references the mesh:
// src/components/MeshLoader.jsx
import MyMeshFile from "./meshes/MyMesh.glb";
import { useGLTF } from "#react-three/drei";
export default function Model(props) {
const group = useRef();
const { nodes, materials } = useGLTF(MyMeshFile);
// Do more stuff with these things
}
When I run compile, everything works, and if I log what MyMeshFile is, I get a path like:
static/media/MyMesh.976a5ad2.glb, as expected.
However, the rest breaks with an error Uncaught Unexpected token e in JSON at position 0, basically on account of the useGLTF function failing at the contents of that file.
It turns out that http://localhost:6006/static/media/MyMesh.976a5ad2.glb is actually a file with the contents of
export default __webpack_public_path__ + "178cb3da7737741d81a5d4f0c2bcc161.glb";
So it seems like there is some redirection happening. If I direct the browser at http://localhost:6006/178cb3da7737741d81a5d4f0c2bcc161.glb, I get the file I want.
My first question, is whether this is the expected behavior here, given the way I have things set up. If so, it seems like I would have to parse the contents of the file path given by Webpack, and use that to get the actual path. That seems to be a bit convoluted, so is there a better way of handling this?
Thanks for the help!
UPDATE:
I have tested with the gltf-webpack-loader loader, by adding the following to the .storybook/main.js file:
...
config.module.rules.push({
test: /\.(gltf)$/, // Removed gltf from file-loader
use: [{loader: "gltf-webpack-loader"}]
})
...
And tried the same thing with a gltf file. I get the same behavior of receiving the "redirect" file instead of the actual one I want.
So it turns out that there is currently a bug with "#storybook/preset-create-react-app" that is causing this issue. Removing that add-on seems to resolve the issue described here, although it does produce a warning that:
Storybook support for Create React App is now a separate preset.
WARN To use the new preset, install `#storybook/preset-create-react-app` and add it to the list of `addons` in your `.storybook/main.js` config file.
WARN The built-in preset has been disabled in Storybook 6.0.
I'm having difficulty with my in-repo addon writing to appDir/public. What I'd like to do is write out a JSON file on each build to be included in the app /dist. The problem I'm running into is when running "ember serve", the file watcher detects the new file and rebuilds again, causing an endless loop.
I've tried writing the JSON file using preBuild() and postBuild() hooks, saving to /public, but after build, the watcher detects it and rebuild over and over, writing a new file again each time. I also tried using my-addon/public folder and writing to that, same thing.
The only thing that partially works is writing on init(), which is fine, except I don't see the changes using ember serve.
I did try using the treeForPublic() method, but did not get any further. I can write the file and use treeForPublic(). This only runs once though, on initial build. It partially solves my problem, because I get the files into app dist folder. But I don't think ember serve will re-run treeForPublic on subsequent file change in the app.
Is there a way to ignore specific files from file watch? Yet still allow files to include into the build? Maybe there's an exclude watch property in ember-cli-build?
Here's my treeForPublic() , but I'm guessing my problems aren't here:
treeForPublic: function() {
const publicTree = this._super.treeForPublic.apply(this, arguments);
const trees = [];
if (publicTree) {
trees.push(publicTree);
}
// this writes out the json
this.saveSettingsFile(this.pubSettingsFile, this.settings);
trees.push(new Funnel(this.addonPubDataPath, {
include: [this.pubSettingsFileName],
destDir: '/data'
}));
return mergeTrees(trees);
},
UPDATE 05/20/2019
I should probably make a new question at this point...
My goal here is to create an auto-increment build number that updates both on ember build and ember serve. My comments under #real_ates's answer below help explain why. In the end, if I can only use this on build, that's totally ok.
The answer from #real_ate was very helpful and solved the endless loop problem, but it doesn't run on ember serve. Maybe this just can't be done, but I'd really like to know either way. I'm currently trying to change environment variables instead of using treeforPublic(). I've asked that as a separate question about addon config() updates to Ember environment:
Updating Ember.js environment variables do not take effect using in-repo addon config() method on ember serve
I don't know if can mark #real_ate's answer as the accepted solution because it doesn't work on ember serve. It was extremely helpful and educational!
This is a great question, and it's often something that people can be a bit confused about when working with broccoli (I know for sure that I've been stung by this in the past)
The issue that you have is that your treeForPublic() is actually writing a file to the source directory and then you're using broccoli-funnel to select that new custom file and include it in the build. The correct method to do this is instead to use broccoli-file-creator to create an output tree that includes your new file. I'll go into more detail with an example below:
treeForPublic: function() {
const publicTree = this._super.treeForPublic.apply(this, arguments);
const trees = [];
if (publicTree) {
trees.push(publicTree);
}
let data = getSettingsData(this.settings);
trees.push(writeFile('/data/the-settings-file.json', JSON.stringify(data)));
return mergeTrees(trees);
}
As you will see the most of the code is exactly the same as your example. The two main differences are that instead of having a function this.saveSettingsFile() that writes out a settings file on disk we now have a function this.getSettingsData() that returns the content that we would like to see in the newly created file. Here is the simple example that we came up with when we were testing this out:
function getSettingsData() {
return {
setting1: 'face',
setting2: 'my',
}
}
you can edit this function to take whatever parameters you need it to and have whatever functionality you would like.
The next major difference is that we are using the writeFile() function which is actually just the broccoli-file-creator plugin. Here is the import that you would put at the top of the file:
let writeFile = require('broccoli-file-creator');
Now when you run your application it won't be writing to the source directory any more which means it will stop constantly reloading 🎉
This question was answered as part of "May I Ask a Question" Season 2 Episode 2. If you would like to see us discuss this answer in full you can check out the video here: https://youtu.be/9kMGMK9Ur4E
I want to build my Dojo JavaScript code that I have carefully structured into packages into a single JavaScript file. I'm a little confused as to how to do it.
For now I have this:
var profile = {
...
layers: {
'app': {
include: [
'dojo/module1',
'dojo/module2',
...,
'dojo/moduleN',
'package2/module1',
'package2/module2',
...,
'package2/moduleN'
]
}
}
...
};
Do I really have to manually add all the modules to the app layer? Can't I just say "all", or better yet, "all referenced"? I don't want to include the dojo/something modul if I don't use it. Also, in my release folder, that's all I would like to have - one file.
So - can this even be achieved? Clean Dojo automatic build of only referenced modules into a single (minified and obfuscated of course) JavaScript file?
Take a look at the examples in the Layers section of this build tutorial:
It’s also possible to create a custom build of dojo.js; this is particularly relevant when using AMD, since by default (for backwards compatibility), the dojo/main module is added automatically by the build system to dojo.js, which wastes space by loading modules that your code may not actually use. In order to create a custom build of dojo.js, you simply define it as a separate layer, setting both customBase and boot to true:
var profile = {
layers: {
"dojo/dojo": {
include: [ "dojo/dojo", "app/main" ],
customBase: true,
boot: true
}
}
};
You can include an entire "app" in a single layer by including the root of that app (or module). Note that if a module in that app is not explicitly required by that app, it would have to be included manually. See the second example in the Layers section in the above tutorial for an illustration of that.
You can also define packages to include in your layers, if you want to change or customize the layout of your project:
packages: [
{name:'dojo', location:'other/dojotoolkit/location/dojo'},
/* ... */
],
layers: {
'dojo/dojo': { include: ['dojo/dojo'] },
/* ... */
}
You don't have to specify all the modules, if the module you add already has dependencies on others. For example, if you include 'app/MainApplication' to a layer, the builder would include all the modules that app/MainApplication depens on. If your MainApplication.js touches everything in your project, everything would be included.
During the build of a layer, dojo parses require() and define() calls in every module. Then it builds the dependency tree. Nls resources are also included.
In your code, you should name your layer as a file in existing package. In my build, it caused errors when I name a layer with a single word. You should code
var profile =
layers: {
'existingPackage/fileName': {
...
}
}
If you want to have exacltly one file, you have to include 'dojo/dojo' in your layer and specify customBase and boot flags.
Dojo always build every package before building layers. You will always have dojo and dijit folders in your release directory containing minified versions of dojo filies in them.
Just copy the layer file you need and delete everything other.
I am trying to use Knockout external template plugin. Firefox stops in my util.js on this line: infuser.defaults.templateUrl = "/CAS/templates";
It complains that infuser is undefined. If I simply press continue in Firebug, the view loads and loads the template just fine. If I comment that line out, the template does not load and I get a file not found error. So that setting is working despite infuser is not defined. Here is the order stuff gets loaded.
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/external/jquery-{version}.js",
"~/Scripts/external/jquery-ui-1-10.2.js",
"~/Scripts/external/jquery.unobtrusive*",
"~/Scripts/external/jquery.validate*"));
bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
"~/Scripts/external/knockout-{version}.js",
"~/Scripts/external/koExternalTemplateEngine_all.js",
"~/Scripts/local/utils.js",
"~/Scripts/external/knockout.mapping-latest.js"));
bundles.Add(new ScriptBundle("~/bundles/local").Include(
"~/Scripts/local/ajaxservice.js",
"~/Scripts/local/DMS.CAS.Dataservice.js",
"~/Scripts/local/DMS.CAS.ViewModel.js",
"~/Scripts/local/DMS.Models.js"));
Here is binding in the view:
<div data-bind="template: {name: 'HelloWorld'}"></div>
My jQuery version is 2.0.3, KO version is 2.3.0, and the KO External Template plugin was installed via nuGet 1 day ago. I have pursued this as problem with the order script files being loaded in the wrong order. But, that does not seem to be the case. Any help is appreciated.
You need to put infuser.js into Knockout bundle before koExternalTemplateEngine_all.js:
bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
"~/Scripts/external/knockout-{version}.js",
"~/Scripts/external/infuser.js",
"~/Scripts/external/koExternalTemplateEngine_all.js",
"~/Scripts/local/utils.js",
"~/Scripts/external/knockout.mapping-latest.js"));
I'm currently trying to develop a custom password manager in c++.
I've already developed a deployable module implementing the nsILoginManagerStorage interface, can install it on firefox and it is being called properly by firefox when a password field appears.
The problem is that when I try to instantiate the nsILoginInfo objects to be returned, the do_CreateInstance function is always returning null.
My method implementation is:
NS_IMETHODIMP FirefoxComponent::FindLogins(uint32_t *count, const nsAString & aHostname, const nsAString & aActionURL, const nsAString & aHttpRealm, nsILoginInfo * **logins)
{
nsILoginInfo ** array = static_cast<nsILoginInfo**>(nsMemory::Alloc(sizeof(nsILoginInfo*)));
nsresult result;
nsCOMPtr<nsILoginInfo> loginInfo = do_CreateInstance("#mozilla.org/login-manager/loginInfo;1" , &result);
//nsCOMPtr<nsILoginManager> loginInfo = do_CreateInstance("#mozilla.org/login-manager;1" , &result);
if (NS_FAILED(result)){
printf("shouldn't be here!!\n");
return result;
}
}
I've tried getting an nsILoginManager instance (just to check if it worked) but it had the same result. The nsILoginInfo can be instantited by java script on firefox using:
Components.classes["#mozilla.org/loginmanager/loginInfo;1"].createInstance(Components.interfaces.nsILoginInfo);
I'm using firefox 20.0 and xul-runner-sdk 20.0 (same results with 20.0.1), on Ubuntu x64, and building with QtCreator (for x64).
My code has been inspired from https://github.com/infinity0/mozilla-gnome-keyring
Since I now that nsILoginInfo is properly loaded into firefox, is there any required field/information for firefox to allow me to access these interfaces?
Thanks for the support.
edit:
Tried to load the module by accessing the component manager directly, but I cannot load the component manager.
nsIComponentManager * manager;
result = NS_GetComponentManager(&manager);
if (NS_FAILED(result)){
printf("failed getting component manager!!\n");
return result;
}
After lots of trial and error I discovered that this error was due to bad linking of the libraries. I was missing one library (libxpcom.so).
To compile and run it right i use the libraries libxpcom.so and libxpcomglue_s.a, both found at the gecko sdk/xul-runner lib folder.
More information about which libraries to compile with in each platform:
https://developer.mozilla.org/en-US/docs/XPCOM_Glue