Svelte/Sapper - Encountered a build related bug with Luxon & Lodash - node.js

So I've just rolled out a new page (dashboard.svelte) on my prototype booking management app - I committed it along with a bunch of other changes and deployed to my Bitnami Node.js (Ubuntu 16.04) VPS.
Builds fine, but when loading any of the site in the browser, I get a bizarre error in the console which breaks execution of all other JS.
TypeError: Kn is not a function which ties back to the return Kn(t... section of a file called map.xxx.js:
var Kn, Xn = function (t, e) {
return function (n, r) {
if (null == n) return n;
if (!qe(n)) return t(n, r);
for (var i = n.length, o = e ? i : - 1, a = Object(n); (e ? o-- : ++o < i) && !1 !== r(a[o], o, a); );
return n
}
}(function (t, e) {
return t && Qn(t, e, Pe)
}); var tr = function (t, e) {
var n = - 1,
r = qe(t) ? Array(t.length) : [
];
return Kn(t, function (t, i, o) {
r[++n] = e(t, i, o)
}),
r
};
I spent several hours trying to track down the source of this bug (which to be honest is not very intuitive), and through trial and error tied it back to the aforementioned dashboard.svelte file (which works fine in npm run dev by the way)
https://gist.github.com/Bandit/58500ebc473e7d8d84bfb6ae16d41ea6
I've put all the information I can find about this in the above gist. I really hope someone can shed some light on the issue because I've had to rollback to an earlier commit for now.
FWIW I use DateTime via Luxon and several lodash methods elsewhere in the application without any issues, so it's not like this is the first time these packages have been built.
/EDIT1 Should note that if I rm src/routes/dashboard.svelte then npm run build everything works fine, so it's completely constrained to that one file...
/EDIT2 Commenting out the following lines in dashboard.svelte makes everything work fine:
// import merge from 'lodash/merge';
// const { session } = stores();
// $session.prefs = merge({}, $session.prefs);
But this makes no sense to me because this EXACT code exists in another page within my app:
import merge from 'lodash/merge';
import { onMount } from 'svelte';
import { hideAll } from 'tippy.js';
import { numberWithOrdinal } from './_helpers.js';
import { hasRole } from 'user.js';
const { session } = stores();
$session.prefs = merge({}, $session.prefs);
So it's something to do with the order of the imports?
/EDIT3 Regarding my comment below with the callstack, this is the line that triggers the issue (which is in a totally different file to dashboard.svelte and runs fine on the server):
$: if (dates && availableItems && availableBookings) populateGrid();
/EDIT4 So after extensive debugging we managed to pin it down to lodash.sortBy. Not sure why that is suddenly an issue as I've been using it for weeks without problem on another page within the app. Anyway I've removed all traces of it for now and all is well. For now (because I don't believe that is truly the issue)...

It's harder to debug because the JavaScript has been uglified.
In your rollup.config.js disable the terser plugin. (You can just comment it out)
Then re-run your build and it should give you non-mangled naming.
Another debugging tip is to edit the JS file map.xyz.js and add a debugger statement right before the line causing the error. Then re-run with devtools open. It will stop at that line and display the call stack. Look thru the call stack, it may shed light on where it's coming from.

Related

Can asynchronous module definitions be used with abstract syntax trees on v8 engine to read third party dependencies? This is for Cloudflare Workers

I understand eval string-to-function is impossible to use on the browsers' application programming interfaces, but there must be another strategy to use third party dependencies without node.js on v8 engine, given Cloudflare does it in-house, unless they disable the exclusive method by necessity or otherwise on their edge servers for Workers. I imagine I could gather the AST of the commonjs module, as I was able to by rollup watch, but what might the actual steps be, by tooling? I mention AMD for it seems to rely on string-to-function (to-which I've notice Mozilla MDN says nothing much about it).
I have been exploring the require.js repositories, and they either use eval or AST
function DEFNODE(type, props, methods, base) {
if (arguments.length < 4) base = AST_Node;
if (!props) props = [];
else props = props.split(/\s+/);
var self_props = props;
if (base && base.PROPS) props = props.concat(base.PROPS);
var code = "return function AST_" + type + "(props){ if (props) { ";
for (var i = props.length; --i >= 0; ) {
code += "this." + props[i] + " = props." + props[i] + ";";
}
var proto = base && new base();
if ((proto && proto.initialize) || (methods && methods.initialize))
code += "this.initialize();";
code += "}}";
//constructor
var cnstor = new Function(code)();
if (proto) {
cnstor.prototype = proto;
cnstor.BASE = base;
}
if (base) base.SUBCLASSES.push(cnstor);
cnstor.prototype.CTOR = cnstor;
cnstor.PROPS = props || null;
cnstor.SELF_PROPS = self_props;
cnstor.SUBCLASSES = [];
if (type) {
cnstor.prototype.TYPE = cnstor.TYPE = type;
}
if (methods)
for (i in methods)
if (HOP(methods, i)) {
if (/^\$/.test(i)) {
cnstor[i.substr(1)] = methods[i];
} else {
cnstor.prototype[i] = methods[i];
}
}
//a function that returns an object with [name]:method
cnstor.DEFMETHOD = function (name, method) {
this.prototype[name] = method;
};
if (typeof exports !== "undefined") exports[`AST_${type}`] = cnstor;
return cnstor;
}
var AST_Token = DEFNODE(
"Token",
"type value line col pos endline endcol endpos nlb comments_before file raw",
{},
null
);
https://codesandbox.io/s/infallible-darwin-8jcl2k?file=/src/mastercard-backbank/uglify/index.js
https://www.youtube.com/watch?v=EF7UW9HxOe4
Is it possible to make a C++ addon just to add a default object for
node.js named exports or am I Y’ing up the wrong X
'.so' shared library for C++ dlopen/LoadLibrary (or #include?)
“I have to say that I'm amazed that there is code out there that loads one native addon from another native addon! Is it done by acquiring and then calling an instance of the require() function, or perhaps by using uv_dlopen() directly?”
N-API: An api for embedding Node in applications
"[there is no ]napi_env[ just yet]."
node-api: allow retrieval of add-on file name - Missing module in Init
Andreas Rossberg - is AST parsing, or initialize node.js abstraction for native c++, enough?
v8::String::NewFromUtf8(isolate, "Index from C++!");
Rising Stack - Node Source
"a macro implicit" parameter - bridge object between
C++ and JavaScript runtimes
extract a function's parameters and set the return value.
#include <nan.h>
int build () {
NAN_METHOD(Index) {
info.GetReturnValue().Set(
Nan::New("Index from C++!").ToLocalChecked()
);
}
}
// Module initialization logic
NAN_MODULE_INIT(Initialize) {
/*Export the `Index` function
(equivalent to `export function Index (...)` in JS)*/
NAN_EXPORT(target, Index);
}
New module "App" Initialize function from NAN_MODULE_INIT (an atomic?-macro)
"__napi_something doesn't exist."
"node-addon-API module for C++ code (N-API's C code's headers)"
NODE_MODULE(App, Initialize);
Sep 17, 2013, 4:42:17 AM to v8-u...#googlegroups.com "This comes up
frequently, but the answer remains the same: scrap the idea. ;)
Neither the V8 parser nor its AST are designed for external
interfacing. In particular (1) V8's AST does not necessarily reflect
JavaScript syntax 1-to-1, (2) we change it all the time, and (3) it
depends on various V8 internals. And since all these points are
important for V8, don't expect the situation to change.
/Andreas"
V8 c++: How to import module via code to script context (5/28/22, edit)
"The export keyword may only be used in a module interface unit.
The keyword is attached to a declaration of an entity, and causes that
declaration (and sometimes the definition) to become visible to module
importers[ - except for] the export keyword in the module-declaration, which is just a re-use of the keyword (and does not actually “export” ...entities)."
SyntheticModule::virtual
ScriptCompiler::CompileModule() - "Corresponds to the ParseModule abstract operation in the ECMAScript specification."
Local<Function> foo_func = ...;//external
Local<Module> module = Module::CreateSyntheticModule(
isolate, name,
{String::NewFromUtf8(isolate, "foo")},
[](Local<Context> context, Local<Module> module) {
module->SetSyntheticModuleExport(
String::NewFromUtf8(isolate, "foo"), foo_func
);
});
Context-Aware addons from node.js' commonjs modules
export module index;
export class Index {
public:
const char* app() {
return "done!";
}
};
import index;
import <iostream>;
int main() {
std::cout << Index().app() << '\n';
}
node-addon-api (new)
native abstractions (old)
"Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.12 to 4.0, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect NODE_MODULE_VERSION and get yourself into a macro-tangle[ macro = extern atomics?]."
Scope Isolate (v8::Isolate), variable Local (v8::Local)
typed_array_to_native.cc
"require is part of the Asynchronous Module Definition AMD API[, without "string-to-function" eval/new Function()],"
node.js makes objects, for it is written in C++.
"According to the algorithm, before finding
./node_modules/_/index.js, it tried looking for express in the
core Node.js modules. This didn’t exist, so it looked in node_modules,
and found a directory called _. (If there was a
./node_modules/_.js, it would load that directly.) It then
loaded ./node_modules/_/package.json, and looked for an exports
field, but this didn’t exist. It also looked for a main field, but
this didn’t exist either. It then fell back to index.js, which it
found. ...require() looks for node_modules in all of the parent directories of the caller."
But java?
I won't accept this answer until it works, but this looks promising:
https://developer.oracle.com/databases/nashorn-javascript-part1.html
If not to run a jar file or something, in the Worker:
https://github.com/nodyn/jvm-npm
require and build equivalent in maven, first, use "dist/index.js".
Specifically: [ScriptEngineManager][21]
https://stackoverflow.com/a/15787930/11711280
Actually: js.commonjs-require experimental
https://docs.oracle.com/en/graalvm/enterprise/21/docs/reference-manual/js/Modules/
Alternatively/favorably: commonjs builder in C (v8 and node.js)
https://www.reddit.com/r/java/comments/u7elf4/what_are_your_thoughts_on_java_isolates_on_graalvm/
Here I will explore v8/node.js src .h and .cc for this purpose
https://codesandbox.io/s/infallible-darwin-8jcl2k?file=/src/c.cpp
I'm curious why there is near machine-level C operability in Workers if not to use std::ifstream, and/or build-locally, without node.js require.

TS/Node.js: Getting the absolute path of the class instance rather than the class itself

Is there a way to get the path (__dirname) of the file where an instance of a class was made without passing that into the constructor?
For example,
// src/classes/A.ts
export class A {
private instanceDirname: string;
constructor() {
this.instanceDirname = ??
}
}
// src/index.ts
import { A } from "./classes/A"
const a = new A();
// a.instanceDirname === __dirname ✓
I tried callsite, it worked but I had to do some regex that I'm not happy with to get what I need, I also tried a module called caller-callsite, but that ended up returning the module path, not the path of the file where the instance was made.
Is there a workaround for this?
I would have callers pass in the location information. Sniffing this stuff seems like a code smell to me (pardon the pun). ;-)
But you can do it, by using regular expressions on the V8 call stack from an Error instance, but it still involves doing regular expressions (which you didn't like with callsite), though it's doing them on V8's own stacks, which aren't likely to change in a breaking way (and certainly won't except when you do upgrades of Node.js, so it's easy to test). See comments:
// A regular expression to look for lines in this file (A.ts / A.js)
const rexThisFile = /\bA\.[tj]s:/i;
// Your class
export class A {
constructor() {
// Get a stack trace, break into lines -- this is V8, we can rely on the format
const stackLines = (new Error().stack).split(/\r\n|\r|\n/);
// Find the first line that doesn't reference this file
const line = stackLines.find((line, index) => index > 0 && !rexThisFile.test(line));
if (line) {
// Found it, extract the directory from it
const instanceOfDirName = line.replace(/^\s*at\s*/, "")
.replace(/\w+\.[tj]s[:\d]+$/, "")
.replace(/^file:\/\//, "");
console.log(`instanceOfDirName = "${instanceOfDirName}"`);
}
}
}
Those three replaces can be combined:
const instanceOfDirName = line.replace(/(?:^\s*at\s*(?:file:\/\/)?)|(?:\w+\.[tj]s[:\d]+$)/g, "");
...but I left them separate for clarity; not going to make any performance difference to care about.

Purescript pulp build output generates requirejs error in browser

When I use pulp build -O -t html/main.js and then pulp build -O -I test -m Test.Main -t html/testmain.js (i.e. building main and test) I get two different js output. In the former case, the format is
// Generated by psc-bundle 0.8.2.0
var PS = { };
(function(exports) {
// Generated by psc version 0.8.2.0
"use strict";
var Prelude = require("../Prelude");
var Control_Monad_Eff = require("../Control.Monad.Eff");
exports["main"] = main;
})(PS["Main"] = PS["Main"] || {});
PS["Main"].main();
Please note the require. In the latter case, the require is not in place at all
// Generated by psc-bundle 0.8.2.0
var PS = { };
(function(exports) {
/* global exports */
"use strict";
exports.concatArray = function (xs) {
return function (ys) {
return xs.concat(ys);
};
};
exports.showNumberImpl = function (n) {
/* jshint bitwise: false */
return n === (n | 0) ? n + ".0" : n.toString();
};
})(PS["Prelude"] = PS["Prelude"] || {});
(function(exports) {
// Generated by psc version 0.8.2.0
"use strict";
var $foreign = PS["Prelude"];
var Semigroupoid = function (compose) {
this.compose = compose;
};
Both examples are shorten, but the point is that require is used in the first time, while not used in the second time.
The issue is that I am not able to run the version using require in the browser due to this error
ReferenceError: require is not defined
When I included require.js into page, I got this error
Error: Module name "../Prelude" has not been loaded yet for context: _. Use require([])
http://requirejs.org/docs/errors.html#notloaded
Thus my question is, what can be done to run the first case in browser.
My guess would be that this comes from running builds with different --require-path options; once with the old default, which was an empty string, and once with ../. This would lead to psc-bundle not realising it needed to include Prelude and Control.Monad.Eff properly in the first case. psc-bundle should replace those require calls with references to the other modules, so that the code works in browsers.
There are a few different ways this can happen, and the compiler has been updated now in a way that should make the probability of this happening again much lower, so I wouldn't spend too much time worrying about exactly how this has occurred.
If none of the above makes any sense to you, don't worry; I think you just need to do the following to fix this:
Update to the latest version of psc (0.8.3 changed the --require-path default to ../, so any version after 0.8.3 should do, but you will want the latest version in most cases)
Delete your output directory
Compile everything again.
You probably need to use the --browserify option to build the first case for the browser.

Coded UI Tests don't run on one machine, but run on another

My co-workers and I are working on a Coded UI project. We both have the same version of the project thanks to TFS, but on his computer all the test cases run, and on mine they don't. They used to run perfectly fine on my machine until one morning they decided to not work. I always keep getting the same error that the UI Test Controls are not found, even though the mappings are correct. Let me remind you that they work perfectly fine on my co-workers machine. We also have the same version of IE (11).
What could be the cause for this?
Thanks for the help in advance.
My co-worker seemed to resolve the situation, but we still don't understand why the previous version of the code worked for everyone but my machine. The problem occurred in our LaunchBrowser method which would use 2 different instantiations of the browser variable. He got rid of the unnecessary one and the playback commands and seemed to have fixed the problem.
Below are two versions of the code, the previous one and the newly written one:
Old:
public static void LaunchBrowser(string url)
{
GlobalVariable.browser = new BrowserWindow();
CloseAllBrowsers();
BrowserWindow.CurrentBrowser = GlobalVariable.BrowserType;
Playback.PlaybackSettings.WaitForReadyLevel = Microsoft.VisualStudio.TestTools.UITest.Extension.WaitForReadyLevel.Disabled;
GlobalVariable.browser = BrowserWindow.Launch();
System.Uri URI = new System.Uri(url);
GlobalVariable.browser.NavigateToUrl(URI);
Playback.PlaybackSettings.WaitForReadyLevel = Microsoft.VisualStudio.TestTools.UITest.Extension.WaitForReadyLevel.UIThreadOnly;
GlobalVariable.browser.Maximized = true;
if (BrowserWindow.CurrentBrowser == "Firefox")
{
Mouse.Click(_fireFoxAuthOK);
}
Logging.WriteLog("Browser was navigated to " + url + " in browser: <" + GlobalVariable.BrowserType + ">");
}
New:
public static void LaunchBrowser(string url)
{
CloseAllBrowsers();
BrowserWindow.CurrentBrowser = GlobalVariable.BrowserType;
GlobalVariable.browser = BrowserWindow.Launch(new Uri(url));
GlobalVariable.browser.Maximized = true;
if (BrowserWindow.CurrentBrowser == "Firefox")
{
Mouse.Click(_fireFoxAuthOK);
}
Logging.WriteLog("Browser was navigated to " + url + " in browser: <" + GlobalVariable.BrowserType + ">");
}
I think the problem is in this line :
Playback.PlaybackSettings.WaitForReadyLevel = Microsoft.VisualStudio.TestTools.UITest.Extension.WaitForReadyLevel.UIThreadOnly;
Because the browser's foreground thread is not ready to start the playback. you may try this
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.Disabled;
or different alternative ways in your pc.
Refer this link Mathew Aniyan's Blog for further information.

Derby.js: split client-side only code into several files

I'm trying to split some client-side-only code into several files in a Derby.js project. It has to be client-side only since it's interacting with the TinyMCE editor. So I tried:
app.ready(function(model) {
var tiny = derby.use(require('../../lib/app/TinyMCE'))
//other client-side code
}
and put the following into lib/app/TinyMCE.js:
var derby = require('derby')
module.exports.decorate = 'derby'; //because before I got an 'decorate' is undefined error...
module.exports.TinyMCE = function() {
//code
}
But now I'm getting a object is not a function error.
Am I even on the right track? I also considered putting the code in the public directory, but the cache-expiration of one year makes this rather inconvenient.
Also, is there really no isServer or isClient method to query?
Okay, I don't know whether that's a good way, but I got it working:
module.exports = tiny
tiny.decorate = 'derby'
function tiny() {
//code
}

Resources