In Angular 14 and module federation, what is the correct way to use import.meta.resolve? - import

I'm using Angular 14 and module federation. I want to use import.meta within my remote application to get the absolute path (e.g. starting with "http://") of a resource. In my remote application, I have webpack.config.js configured like so
module.exports = withModuleFederationPlugin({
name: 'my-app',
exposes: {
'./home':'./src/app/my-module/products.module.ts'
},
shared: {
...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
},
});
Then in my service within the remote application, I try and use import.meta.resolve, like so
#Injectable({
providedIn: 'root'
})
export class MyService {
...
public init() {
const absolutePath = import.meta.resolve('./settings.json');
but this throws the compilation error, "Cannot invoke an object which is possibly 'undefined'.". What is the proper way to invoke the "resolve" method in order to get an absolute path of a resource?

I think you need to add a parent absolute path as follow :
const absolutePath = await import.meta.resolve('./settings.json', parent);
that resolves a relative specifier in regards to a parent absolute path.
parent argument is optional and defaults to the current module absolute path.
Let's say that you have a module main.mjs under the absolute path /home/user/web-app/main.mjs. You also have a module helper.mjs that is located in the same folder as main.mjs. You'd like to get the absolute path to helper.mjs.
Here's how you could do it:
// main.mjs
const resolvedPath = await import.meta.resolve('./helper.mjs');
console.log(resolvedPath); // '/home/user/web-app/helper.mjs'
Executing await import.meta.resolve('./helper.mjs') would resolve ./helper.mjs to /home/user/web-app/helper.mjs absolute path.
If the resolved module doesn't exist, then the function would throw a module not found error.
Here is a very good article that may give you more details :
https://dmitripavlutin.com/javascript-import-meta/

Related

NetSuite SuiteScript - Constants And Inclusion

I have a NetSuite SuiteScript file (2.0) in which I want to include a small library of utilities I've built. I can do that fine, and access the functions in the included library. But I can't access the constants I've defined in that library - I have to re-declare them in the main file.
Here's the main file:
define(['N/record', 'N/search', './utils.js'],
function (record, search, utils) {
function pageInit(scriptContext) {
isUserAdmin = isCurrentUserAdmin(contextRecord);
if (isUserAdmin) {
alert('Administrator Role ID is ' + ADMINISTRATOR_ROLE);
// Do something for Admin users
}
return;
}
return {
pageInit: pageInit
};
});
You can see I include the file ./utils.js in it. Here's utils.js:
const ADMINISTRATOR_ROLE = 11;
function isCurrentUserAdmin(currentRecord) {
return ADMINISTRATOR_ROLE == nlapiGetRole();
}
That's the entire file - nothing else.
In the main file, the call to the function isCurrentUserAdmin works fine. It correctly tells me whether the current user is an admin. Note that I don't have to preface the call to isCurrentUserAdmin with utils. (utils.isCurrentUserAdmin doesn't work - it gives me the error JS_EXCEPTION TypeError utils is undefined). But when the code gets to the line that uses ADMINSTRATOR_ROLE, I get the error JS_EXCEPTION ReferenceError ADMINISTRATOR_ROLE is not defined. BTW, if I put the constant definition of ADMINISTRATOR_ROLE in the main file instead of utils.js, I get the same error when utils.js tries to use it. The only way I can get it to work is if I have the line defining the constant in both files.
Why does the inclusion work for the function, but not the constant? Am I including the library wrongly? I thought I'd have to use it as utils.isCurrentUserAdmin rather than just isCurrentUserAdmin, but to my surprise that's not the case, as I say above.
If you have utils.js like below, you can use utils.ADMINISTRATOR_ROLE and utils.isCurrentUserAdmin() in your main file.
/**
*#NApiVersion 2.0
*/
define ([],
function() {
const ADMINISTRATOR_ROLE = 11;
function isCurrentUserAdmin() {
// check here
}
return {
ADMINISTRATOR_ROLE: ADMINISTRATOR_ROLE,
isCurrentUserAdmin: isCurrentUserAdmin
};
});
Try
define(['N/record', 'N/search', 'SuiteScripts/utils']
You need to make sure any member you need to access in another module needs to be exported in the source module using the return statement

nextjs import but don't invoke function throws Module not found: Error: Can't resolve 'dns'

My project(NextJS) was working fine and suddenly I am experiencing the issue ModuleNotFoundError. Particularly in the case of dynamic routing of nextJs.
Error I see is: Module not found: Error: Can't resolve 'dns'
In the pages directory pages/programs/[programtype]/[program].jsx when mongo is imported, it throws:
ModuleNotFoundError: Module not found: Error: Can't resolve 'dns' in 'node_modules/mongodb/lib'
Full error dump:
ModuleNotFoundError: Module not found: Error: Can't resolve 'dns' in '/project-path/node_modules/mongodb/lib'
at /project-path/node_modules/webpack/lib/Compilation.js:925:10
at /project-path/node_modules/webpack/lib/NormalModuleFactory.js:401:22
at /project-path/node_modules/webpack/lib/NormalModuleFactory.js:130:21
at /project-path/node_modules/webpack/lib/NormalModuleFactory.js:224:22
at /project-path/node_modules/neo-async/async.js:2830:7
at /project-path/node_modules/neo-async/async.js:6877:13
at /project-path/node_modules/webpack/lib/NormalModuleFactory.js:214:25
at /project-path/node_modules/enhanced-resolve/lib/Resolver.js:213:14
at /project-path/node_modules/enhanced-resolve/lib/Resolver.js:285:5
at eval (eval at create (/project-path/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
at /project-path/node_modules/enhanced-resolve/lib/UnsafeCachePlugin.js:44:7
at /project-path/node_modules/enhanced-resolve/lib/Resolver.js:285:5
at eval (eval at create (/project-path/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
at /project-path/node_modules/enhanced-resolve/lib/Resolver.js:285:5
at eval (eval at create (/project-path/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:25:1)
at /project-path/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43
The problem
This is a subtle problem with server-side code in Next.js.
The error is clear - you're trying to execute server side code (mongo query) in a client side code. But the cause is not obvious, because with Next.js you should be able to call Mongo from your components.
The cause
Next.js throws this error because you are importing your mongo code without using it.
It sounds weird but it is true.
How to avoid it
To avoid this error just remove any server-side code import in your components if you don't use it in getServerSideProps.
It sounds even more weird but it is true.
Good and bad examples
This works fine:
import { findUsers } from '../lib/queries'
function Home({ users }) {
return (
<h1>Users list</h1>
//users.map and so on...
)
}
export async function getServerSideProps() {
const users = await findUsers()
return {
props: {
users: users
}
}
}
export default Home
While this will throw the error:
import { findUsers } from '../lib/queries'
function Home({ users }) {
return (
<h1>Users list</h1>
//users.map and so on...
)
}
export async function getServerSideProps() {
// call disabled to show the error
// const users = await findUsers()
return {
props: {
users: [] //returning an empty array to avoid other errors
}
}
}
export default Home
Keep your server-side coding modules (for e.g: models, database connection maker) outside of the Page directory.
For reference: https://nextjs.org/docs/messages/prerender-error
If you're getting this error with Next-js auth, make sure your "lib" folder is in the root directory.
Here's the structure
my problem was that i used a function in initialprops wich was exported via module.exports instead of export default
I created a directory called 'api-lib' in my project root directory to add my queries and that caused this error to appear.
And I solved it by moving my 'api-lib' directory into the main 'src' directory.
My issue was exporting getServerSideProps with all of it's server side operations from a component, where it should only be placed and exported from a PAGE component.
Moving getServerSideProps to the main page component and just drilling down what I needed to the child component solved it for me.

Using TypeScript with Dojo - import/export issues

In the company I work for we are using Dojo framework and lately I have started pushing to use it with TypeScript.
I took a look around and found this great article on how this topic, you can find it here:
https://gregwiechec.com/2016/01/creating-dojo-widget-in-typescript/
The last 2 lines in this solution are:
var exp = _declare("alloy.editors.StringListTs", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _CssStateMixin, _ValueRequiredMixin], new StringList());
export = exp;
I followed the same pattern and it works great, except for 2 issues that I cant seem to have a good solid solution:
1. If you look at the solution, when calling dojo declare method, the class created needs to be instantiated (this is because dojo looks at properties and not prototype).
2. The more problematic issue, is the fact that I am exporting out the dojo declared object, and not the class it self. This is problematic when you try to import the class (typescript import), and even if I declare the variable exp as the class type, I get an error saying that there is no constructor to what i am trying to import.
I faced your same problem, and for me has been a transpiler issue.
TL;DR if you import something using the import * as WidgetName from '<path>' syntax and don't use WidgetName in the js (like you would do for a widget in a template), the transpiler won't import it. Use import '<path>' instead.
Long answer: It's my first time with TypeScript and, similarly you, I'm converting a dojo project to TypeScript. Hoping to help more people, I'll put few steps which helped me to import modules correctly.
Step 0 dojoConfig packages
Defining you own package on dojoConfig won't work, modules must be referenced using relative path.
To be clear, with this example:
dojoConfig = {
...
packages : [ { name : "myproject", location : "js/myproject" },
{ name : "dojo", location : dojoBase+"dojo" },
{ name : "dijit", location : dojoBase+"dijit" },
{ name : "dojox", location : dojoBase+"dojox" } ]
};
It's not possible to have widget importing each other with import * as WidgetName from 'myproject/WidgetName' approach, but rather you have to import * as WidgetName from './WidgetName' (notice the '.' vs 'myproject').
Step 1: importing dojo declaration (not mandatory, as far as I noticed)
I'm relying on node, I pulled dojo-typing using npm install dojo-typings --save-dev. In the files property I specified [ "src/js/**/*.ts", "src/js/**/*.js", "node_modules/dojo-typings/dojo/1.11/index.d.ts", "node_modules/dojo-typings/dojo/1.11/modules.d.ts", "node_modules/dojo-typings/dijit/1.11/index.d.ts", "node_modules/dojo-typings/dijit/1.11/modules.d.ts" ].
Step 2: using the correct options on the transpiler:
{
"target": "es5",
"allowJs": true,
"module": "amd",
"moduleResolution": "classic",
"noImplicitUseStrict" : true
},
noImplicitUseStrict solved the error dojo/parser::parse() error TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them. allowJs allowed me to mix TypeScript and native dojo together.
Step 3: returning using export
This is an example of a very minimal module which doesn't require/import anything, but only exports a log method (file would be 'toast.ts'):
const log = function(message) {
window['dojo'].publish("mainTopic",
[{
message: "<span style='font-size: 12px;'>" + message +"</span>",
type: 'info',
duration: 3000
}]
);
}
export { log }
For completeness, in pure Dojo you would have written something like (file would be 'toast.js'):
define([ ],
function(){
var log = function(message) {
dojo.publish("mainTopic",
[{
message: "<span style='font-size: 12px;'>" + message +"</span>",
type: 'info',
duration: 3000
}]
);
};
return { log : log };
});
Step 4: rewrite your widget and import it correctly
I use a Main widget which takes all the body, here the content of Main.ts:
/// <amd-dependency path="dojo/text!./Main.html" name="template" />
declare var template: string;
import * as _Widget from 'dijit/_Widget';
import * as _TemplatedMixin from 'dijit/_TemplatedMixin';
import * as _WidgetsInTemplateMixin from 'dijit/_WidgetsInTemplateMixin';
import * as dojoDeclare from 'dojo/_base/declare';
import './MyVanillaJavascriptWidget';
import './MyModule';
import 'dojox/widget/Toaster';
import toast = require('./utility/toast');
export default dojoDeclare("mm.Main", [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ], {
templateString : template,
});
There are different types of imports:
the first is the one I struggled the most, for the template
import * as ... is a sequence of dojo objects I use in the class
import '<path>' is used for widget I declared in the template using data-dojo-type
import name = require('<path>') is another way to require modules
For completeness, this would be the original Main.js file:
define([ "dijit/_Widget", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
"dojo/_base/declare", "dojo/text!./Main.html",
"dojox/widget/Toaster", "./MyVanillaJavascriptWidget", "./MyModule"
],
function( _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, declare, mainTemplate, toast) {
return declare("mm.Main", [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ], {
templateString : mainTemplate,
});
});
Conclusion: The missing constructor most probably comes from the way you import a module, checking the transpiled code helped me to understand where the issue was. To succeed with the import, a bit of accuracy is needed here and there (all the steps above should give an overview).
I'm still in the process of converting my project (other issues may come out), but I hope this helps also other poor souls trying to use TypeScript with Dojo!

Ext.define() order

I'm using Extjs5 and Sencha Cmd, and I'm working on a l10n engine (over gettext) to implement localization.
Suppose I want to offer a translation function to every class of my project, named _().
In every controller, view, model and any class, I'd like to be able to write something like that:
Ext.define('FooClass', {
someStrings: [
_('One string to translate'),
_('A second string to translate'),
_('Yet another string to translate')
]
});
First problem: _() must exist before all the Ext.define() of my project are executed. How to achieve that?
Second problem: _() is looking in "catalogs" that are some JavaScript files generated from .po files (gettext). So, those catalogs must have been loaded, before all the Ext.define() of my app are executed.
_() is a synchronous function, it musts immediately return the translated string.
Edit concerning the edited question
You have at least two ways to load External libraries:
Ext.Loader.loadScript
loadScript( options )
Loads the specified script URL and calls the supplied callbacks. If
this method is called before Ext.isReady, the script's load will delay
the transition to ready. This can be used to load arbitrary scripts
that may contain further Ext.require calls.
Parameters
options : Object/String/String[] //The options object or simply the URL(s) to load.
// options params:
url : String //The URL from which to load the script.
onLoad : Function (optional) //The callback to call on successful load.
onError : Function (optional) //The callback to call on failure to load.
scope : Object (optional) //The scope (this) for the supplied callbacks.
If you still run into problems you can force the loader to do a sync loading:
syncLoadScripts: function(options) {
var Loader = Ext.Loader,
syncwas = Loader.syncModeEnabled;
Loader.syncModeEnabled = true;
Loader.loadScripts(options);
Loader.syncModeEnabled = syncwas;
}
Place this in a file right after the ExtJS library and before the generated app.js.
Old Answer
You need to require a class when it is needed, that should solve your problems. If you don't require sencha command/the ExtJS class system cannot know that you need a specific class.
Ext.define('Class1', {
requires: ['Class2'],
items: [
{
xtype: 'combo',
fieldLabel: Class2.method('This is a field label')
}
]
});
For further reading take a look at:
requires
requires : String[]
List of classes that have to be loaded before instantiating this
class. For example:
Ext.define('Mother', {
requires: ['Child'],
giveBirth: function() {
// we can be sure that child class is available.
return new Child();
}
});
uses
uses : String[]
List of optional classes to load together with this class. These
aren't neccessarily loaded before this class is created, but are
guaranteed to be available before Ext.onReady listeners are invoked.
For example:
Ext.define('Mother', {
uses: ['Child'],
giveBirth: function() {
// This code might, or might not work:
// return new Child();
// Instead use Ext.create() to load the class at the spot if not loaded already:
return Ext.create('Child');
}
});
Define the translate function outside the scope of the ExtJs project and include it before the Ext application is included in the index.html.
The scripts are loaded in the right order and the _() function is ready to use in your whole project.
i18n.js
function _() {
// do the translation
}
index.html
<html>
<head>
<script src="i18n.js"></script>
<script id="microloader" type="text/javascript" src="bootstrap.js"></script>
</head>
<body>
</body>
</html>

Set default value for static method in bootstrap

this paragraph is part of 'Zend Framework In Action' book.
SearchIndexer::setIndexDirectory(ROOT_DIR . '/var/search_index');
Places_Db_Table_Row_Observable::attachObserver('SearchIndexer');
As you can see, it’s simply a case of setting the directory to store the search index files
and attaching the class to the list of observers in Places_Db_Table_Row_Observable
using the name of the class.
Now I have a problem! I put this code in bootstrap file in runapp method, but it can't recognize the directory that I set in bootstrap!
It shows me this error
An error occurred exception 'Zend_Search_Exception' with message 'No index directory specified' in E:\xampp\php\PEAR\Zend\Search\Lucene.php:497
=======================================================
other type of my question :
I have this code in bootstrap file (runApp method):
SearchIndexer::setIndexDirectory(ROOT_DIR.'/var/search_index');
Places_Db_Table_Row_Observable::attachObserver('SearchIndexer');
I set search directory path in SearchIndexer class, but there is a prob!
When I use of below code in controller action, it can't recognize the directory that I set in bootstrap!
controller code :
$index = Places_Search_Lucene::open(SearchIndexer::getIndexDirectory());
this is seachIndexer code :
public static function setIndexDirectory($directory){
if(!is_dir($directory)) {
throw new Exception('Directory for SearchIndexer is invalid ('. $directory .')');
}
self::$_indexDirectory = $directory;
}
public static function getIndexDirectory(){
return self::$_indexDirectory;
}
Your getIndexDirectory function does not return a path so Places_Search_Lucene::open fails.
Maybe setIndexDirectory fails to set the path. Do some debugging on that.
Maybe you use the class in your bootstrap before it gets loaded by zend autoloader. Where do you perform this?
Try to load the class manually before usage:
Zend_Loader::loadClass('Path_To_SearchIndexer',
array(
'/home/production/mylib',
)
);
Documentation on zend loader: http://framework.zend.com/manual/en/zend.loader.load.html