Welcome

This is my personal web space. Please forgive the broken articles, Markdown/Textile are not very forgiving after multiple blog software changes!

Dealing with ReferenceError can't access lexical declaration before initialization issues in an Angular application

Posted on: 2022-10-20 17:11:59

So, there you are, minding your own business when you start getting an error that looks like this:

ERROR Error: Uncaught (in promise): ReferenceError: can't access lexical declaration 'NewState' before initialization NewState@http://localhost:8100/default-src_app_modules_messaging_messaging-components_messaging-components_module_ts-src_app_pages-f15b60.js:248:64 
46129@http://localhost:8100/default-src_app_modules_messaging_messaging-components_messaging-components_module_ts-src_app_pages-f15b60.js:613:8 
__webpack_require__@http://localhost:8100/runtime.js:23:42 
3982@http://localhost:8100/default-src_app_modules_messaging_messaging-components_messaging-components_module_ts-src_app_pages-f15b60.js:258:99 
__webpack_require__@http://localhost:8100/runtime.js:23:42 
9851@http://localhost:8100/default-src_app_modules_messaging_messaging-components_messaging-components_module_ts-src_app_pages-f15b60.js:218:102 
__webpack_require__@http://localhost:8100/runtime.js:23:42 
78016@http://localhost:8100/src_app_modules_chat_pages_chat-messages_chat-messages_module_ts.js:22:138 
__webpack_require__@http://localhost:8100/runtime.js:23:42

If you search for this error, you'll find lots of links to the MDN article on ReferenceError but this isn't helpful. Beacuse at this point you've got TypeScript + Webpack mangling your output so badly that you have absolutely no idea what's going on.

Well, here's the thing, Angular & Webpack do a pretty good job of making sure that you're not hoisting things out of order or doing weird things with your dependency. Here's your real problem:

You've got a circular dependency

But wait, doesn't Angular already check for circular dependencies? Yeah. Obvious ones, they sure do. You can't have an NgModule that references another NgModule which references back to the other NgModule. It would detect that and throw an error.

Here's an example: https://stackblitz.com/edit/angular-ivy-ez3evu?file=one.module.ts,two.module.ts

It doesn't even compile. It just stack overflows.

I tried to reproduce the actual issue we had in StackBlitz... it didn't work.

The truth is, some circular references are just not detected without a bit of extra work.

Angular CLI to the rescue: ng build --show-circular-dependencies

Warning: Circular dependency detected:
src/app/modules/chat/state/conversations/small-conversation.state.ts -> 
src/app/pages/trainer-messages/trainer-messages.page.ts -> 
src/app/modules/chat/state/conversations/small-conversation.state.ts

This revealed our state model was dependent upon a page... that depends on our state model...? What?

It was an enum

Ultimately, we had an enum in that page's file and that file depended upon the state model itself. Moving that enum to a new file and including it on both pages fixed the issue.

Here's hoping this page helps other people!

Continue reading...

Debugging PHP applications on Ubuntu

Posted on: 2022-04-19 15:57:13

I'm cleaning out some notes and wanted to put this somewhere...

On Ubuntu

  • Crashes go to /var/crash.
  • Make sure ulimit -c unlimited is run. Restart php-fpm.

Or see: https://bugs.php.net/bugs-generating-backtrace.php

In order to “unpack them” you use apport-unpack <crash> ~/destination.

See: https://askubuntu.com/questions/434431/how-can-i-read-a-crash-file-from-var-crash

Then, you can use gdb cat ExecutablePath CoreDump within that directory to examine it.

You’ll need the debug symbols loaded for php-fpm. If you’re using the one from sury: https://github.com/oerdnj/deb.sury.org/issues/512

Basically, add the main/debug repos and then apt-get install the correct php7.4-fpm-dbgsym (or 8.0, whatever, you do you)

You also probably want the dbg helpers for zend: https://reverseengineering.stackexchange.com/questions/9558/how-to-get-current-php-function-name-in-gdb https://derickrethans.nl/what-is-php-doing.html

Get the current version of .gdbinit: https://github.com/php/php-src/blob/master/.gdbinit

Then you can review the stacktraces...

Continue reading...

Strong like steel? What about the mighty oak?

Posted on: 2022-02-03 10:26:32

It's sleeting outside right now and while many people are having flashbacks to the event of last year. But one of the things that came to mind as I looked outside this morning was the trees in the front yard.

When people think about strength, we often think of steel. As in the "Man of Steel". And while steel has been used to create some of the biggest structures in existence, steel isn't perfect for everything.

While steel is strong, steel can form hidden cracks. When it finally does break, it can be catastrophic.

But oaks. Oaks may not be as strong as steel directly. But they are magnificent and mighty.

When it snowed and iced last year, our pin-oak's branches drooped nearly 9 feet until they basically touched the ground. Walking around outside after the snow, you could hear branches of the Juniper (Texas Cedar) trees snapping in the cold and the weight of of the snow.

I can't pull down a branch on my own, but the snow can weigh it down. But after the snow melts, the branches are restored and the oak is no worse for wear.

All that said, when we think about strength, we should consider the oak, which can bend and twist, be stripped naked of its leaves, be taken down nearly to the ground, but yet can withstand it all.

Continue reading...

Hot code updates for Cordova applications

Posted on: 2022-01-23 21:18:27

A long time ago, I used and (mostly) loved Ionic's Live Update (iirc, I think it was called Deploy in the past) functionailty. The idea is really simple. Your "app" lives on-device in a www/ directory that gets served up by Cordova. There really isn't anything magical about it but why can't you just check to see if your application has updates files every time you start it up? And, if it does, update your files and then launch the app?

Well, that's what Live Update does.

There are some caveats, though.

Obviously, the updates can't add/remove/update Swift/Objective-C libraries or modules. Bugs or improvements in those modules can't managed through this method.

The only real "gotcha" here is that Ionic makes you pay for Deploy credits. By default you currently get 25k per month. This is probably enough if you want to update a small group of users a few times a day, but it isn't enough if you want to push out a large number of updates across the board.

In a way, this whole thing sort-of offends my sensibilities. Why would I pay per-device to deliver a www/ directory, when CDNs and other systems allow me to do this for pennies.

Well, if you're offended by this, like me, then you probably are wondering if there are other options.

Well, sort of.

Here's what I've found in my research.

Looks like there are 2 main options here:

  1. Use the chcp (cordova-hot-code-push) module.
  2. Set up Appflow Deploy.
Continue reading...

Eloquent upsert() requires a UNIQUE index on MySQL

Posted on: 2021-10-29 16:19:48

tl;dr - upsert() acts different based on your DB. MySQL requires that a UNIQUE INDEX exist for the combination of column you are wanting upsert to work on.

Where I can, I've been using upsert() as a way to make many queries into (usually) a single query.

Recently, I had a situation where a function in our code base was essentially doing this:

$model->relation->delete();
foreach ($anArray as $newModels) {
   $model->relation()->create($anArray);
}

This operation was wrapped in a DB::beginTransaction() / DB::commit().

When I finally got around to re-writing it, it was much cleaner and of course looked something like this:

RelatedModel::upsert(
   $models,
   ['key_one', 'key_two', 'key_three'].
   ['col1', 'col2']
);

I ran the test suite (it passed), pushed and went to sleep.

When I woke up the next morning, I saw a number of errors and a large number of records being generated. Obviously, something was not right in the world of upsert.

After digging into things and exploring how MySQL "compiles" upserts, it turns out that this:

RelatedModel::upsert(
   $models,
   ['key_one', 'key_two', 'key_three'].
   ['col1', 'col2']
);

Also could be written like this:

RelatedModel::upsert(
   $models,
   [].
   ['col1', 'col2']
);

That second set of parameters is never used in the function:

public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
{
    $sql = $this->compileInsert($query, $values).' on duplicate key update ';

    $columns = collect($update)->map(function ($value, $key) {
        return is_numeric($key)
            ? $this->wrap($value).' = values('.$this->wrap($value).')'
            : $this->wrap($key).' = '.$this->parameter($value);
    })->implode(', ');

    return $sql.$columns;
}

$uniqueBy isn't used. It is in the SQLite version, but not here.

After cleaning up the DB and adding an index, the upsert will work as expected.

Continue reading...