Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Kint 6 #422

Open
jnvsor opened this issue Aug 31, 2024 · 23 comments
Open

RFC: Kint 6 #422

jnvsor opened this issue Aug 31, 2024 · 23 comments
Assignees
Labels
Milestone

Comments

@jnvsor
Copy link
Member

jnvsor commented Aug 31, 2024

If you've been paying attention to the repo you may have noticed a lot of commits showing up. Since the PHP 8.4 feature freeze on the 13th I've been working on a new major version with 7.4 as the minimum requirement.

It's essentially ready to go (Though I will only be publishing beta tags for now) but I'd like some feedback since among other things the JS has been completely rewritten and modernized.

I've got much less experience in JS than in PHP so if any JS devs have any suggestions in that area I'd welcome those too.

Semi-complete list of changes:

  • "Open in new window" button has been removed. I for one never used it, and the code involved obfuscation and the likes to get around browser security measures. Basically it was ugly and could break at any time so I figured I'd remove it. If it actually got a lot of use and I get complaints here I can port it back in but I doubt it.
  • Full JS rewrite. Now we stop trying to be clever and just put it in 1 file and dump the whole thing on the first dump of both rich and plain renderers. It's a bit of extra bandwidth but 12kb isn't much when dumping a container from a typical framework is measured in mb.
    • In-browser performance for an "Open everything on the page" operation went from 700ms on 5.1.1 to 100ms in my test script
    • It should handle ajax dumped to the body improperly more gracefully. All functionality should remain operational, including on the new additions, just you'll have some extra script and style tags left over until a Kint.init() run gets triggered somewhere
    • You can now access search from keyboard controls with s and go back to keyboard control with esc
  • kint-ide-link behavior removed. You can set Kint::$file_link_format (or xdebug.file_link_format) to get a link to source code, which is great for opening an editor right to a dump or stack trace frame. It had custom behavior of sending an AJAX request if the link is in http or https protocol that seems to have been used for VERY old phpstorm versions. Nowadays you can just set a protocol link, which is recommended by eg. symfony docs way back in symfony 2
  • "undefined" is now "uninitialized" for php naming consistency
  • Nonces have been moved to AbstractRenderer - old code should still work but now it'll work for plain styles/code too
  • Lots of typehints pretty much everywhere since with 7.4 we now can rely on type hinted properties
  • Internal API breaks for any custom plugins you've written
    • Plugins added by class string alone must now implement Constructable.. interfaces
    • Values now have required parameters in constructors
  • New extensive testing for SimpleXML, DOMDocument, and the new PHP 8.4 Dom\Document stuff. XML related access paths have been made much more succinct
  • Removed prophecy. Just using core phpunit for mocking now
  • ToString, Binary, Mysqli, and DOMDocument plugins are now on by default
  • New HTMLPlugin will change strings starting with <!DOCTYPE html> into Dom\HTMLDocument like the XMLPlugin does
  • Iterators will automatically be the primary representation if the object has no properties (In other words you can see what's in them in text renders)
  • Lots of bugfixes

For now, barring any feedback, I'm going to see if I can eke out more perf with cachegrind

@jnvsor jnvsor added the RFC label Aug 31, 2024
@jnvsor jnvsor added this to the 6 milestone Aug 31, 2024
@jnvsor jnvsor self-assigned this Aug 31, 2024
@jnvsor
Copy link
Member Author

jnvsor commented Sep 6, 2024

6.0-beta2 out

  • Property hooks support:
    image

    I'm not sure if this is the best way to handle it but right now we have it being shown in 2 parts:

    1. Core kint dump adds flags for hook support. This then renders in interface-like syntax in the dump bar
    2. A hook plugin which lets you unfold them like other methods. This has limited use and I may remove it from default later. It doesn't do anything the existing flags don't do other than show where it was defined and what the docstring (If it has one) is
  • Reflection is now the primary source of property information. Before we used array casts for various reasons but now we have tests to guarantee that the properties will be in the order they are looped/cast to across multiple versions (The order changed in 8.1)

    • Array casting was mostly a holdover from the days of 5.2 when reflection couldn't show dynamic properties so it stuck around until there was a reason to change it with 7.4's uninitialized properties
    • Since we now reproduce the order accurately I've removed the renderer's abilities to custom sort properties
  • Added ESlint for the JS side of things

  • Shows SplFileInfo in text renders

  • Made 8.4 the default test version (This fixes psalm's ignorance of the new Dom classes)

  • More tests and bugfixes

@HLeithner
Copy link

Nice work, didn't had the time to look at everything yet but would like to give feedback about

"Open in new window" button has been removed. I for one never used it, and the code involved obfuscation and the likes to get around browser security measures. Basically it was ugly and could break at any time so I figured I'd remove it. If it actually got a lot of use and I get complaints here I can port it back in but I doubt it.

It's something I use sometimes as specially if the view area of kint is really limited, so maybe an button to open a "full screen" model which is on the highest dom level would be an alternative?

@jnvsor
Copy link
Member Author

jnvsor commented Sep 7, 2024

@HLeithner

so maybe an button to open a "full screen" model which is on the highest dom level would be an alternative?

Sounds like you want Kint\Renderer\RichRenderer::$folder = true - this will put your dumps in a folder docked to the bottom of the viewport. I suppose the downside is you have to set this up before dumping. Do you think there'd be interest in a button to do it in JS?

@HLeithner
Copy link

yeah I know the docked function, but for normally use it's a bit not optimal tbh, so with a button it would be a good solution, but I wouldn't but it the bottom, instead on top would be better but that's another story.

@HLeithner
Copy link

Another interesting thing would be to customize the last line (with the stacktrace), I know that doesn't fit into this issue. But adding metadata to the rendered output would be nice, I can of course do this with my own additional line but having this as an programmable interface would be nice.

Example I would like replace the simple stacktrace with an more complex variant (ex. counting the how often a function has been called in this trace (recursion)). Or having a second column with other meta information like how often this this specific kint in this line in this file has been called. Useful for loops. And I'm pretty sure I there is more useful information that could be displayed, like user information, memory usage, cpu spikes, you name it.

I use kint warped in my own joomla plugin which prepare the usage, so filling the kint::statics would be easily possible before outputting kint.

hmm I think that should be move to it's own issue...

@jnvsor
Copy link
Member Author

jnvsor commented Sep 7, 2024

how often this this specific kint in this line in this file has been called. Useful for loops. And I'm pretty sure I there is more useful information that could be displayed, like user information, memory usage, cpu spikes, you name it

Number of calls/memory usage/timing info is there if you dump microtime() repeatedly (Like in a loop) I don't want to duplicate that in the minitrace because it would just be a downgraded version (Though the minitrace does support date() formats which you can set with RichRenderer::$timestamp)

That said, you can (And I have in the past) extend the renderer itself and change whatever you want. All the RichRenderer props/methods are protected so you just subclass it and change the Kint::$renderers entry to your subclass. Then it's just a matter of changing the postRender.

@jnvsor
Copy link
Member Author

jnvsor commented Sep 7, 2024

@HLeithner I've taken a crack at the dynamic-moving-of-the-dumps-to-folder work. Can you try out 055bc6f and see if that does what you want? (It's f in keyboard control mode)

@HLeithner
Copy link

@jnvsor works as expected, on top would be good ;-) and moved back to the position before, but both is not really needed.

I converted my own plugin to this version, a migration guide would be helpful but it wasn't too hard to find out the changes (it's a simple plugin).

Thanks

@HLeithner
Copy link

about the renderer topic

That said, you can (And I have in the past) extend the renderer itself

kint is a moving target which makes it hard to override things like you said, having to adapt own code often is not so fun as it sounds ;-)

we at joomla have a strict semver policy (and sometimes fails) with a stable release cycle of 4 years and people are annoyed that we change anything... of course this tool has a different target group.

never the less I will have a look at this.

@jnvsor
Copy link
Member Author

jnvsor commented Sep 8, 2024

on top would be good

I think you can manage that with just CSS

kint is a moving target which makes it hard to override things

I make no guarantees about JS but kint doesn't break semver on the PHP side (Or else it's a bug and should be reported) Obviously no guarantees about 6.0 before release either

@jnvsor
Copy link
Member Author

jnvsor commented Sep 14, 2024

Beta 3 is now out:

  • The folder is now generated with JS and existing dumps can be moved into the folder with JS
  • JS/CSS rendering has been moved into a trait with caching
  • Added ProfilePlugin: This opt-in plugin will help identify which parts of a dump are making it slow
  • ClassHooksPlugin: Will only show on hooks with a docblock associated unless ClassHooksPlugin::$verbose = true

@HLeithner
Copy link

On the sublevel the complexity is collected in the "Perfomance Profile" tab

image

on the first level the "Performance Profile" shows the complexity for it self and for all subentries

image

"Class Complexity" shows the subentries as a variable dump

image

Is it expected?

@jnvsor
Copy link
Member Author

jnvsor commented Sep 15, 2024

@HLeithner The performance profile is a lot easier to grok if you use it in something massive and complex like a framework's container:

image

  • This node and below it have a complexity of 466
  • This specific instance (with object id 58) appears in 135 places in the dump
  • The combined complexity of all 135 and below them is 62910 -- so this has a much larger performance impact than just the one part of the dump would suggest

This lets you know which specific instances are being used all over the place and making the dump slower, but it doesn't tell you if you have many different instances of a specific class or interface, so class complexity shows the total complexity found under each class/interface:

image

This is much harder to read and full of false postives (Like you probably don't want to blacklist all stringables even if there are a lot of them) but helps if what you're dumping has many heavy instances of the same type.

@HLeithner
Copy link

Ah ok, that makes more sense, that's thanks

@jnvsor
Copy link
Member Author

jnvsor commented Sep 23, 2024

6.0-beta4:

  • Static properties and constants will now be split into separate tabs
  • Static properties and constants from parent classes (Overridden or private) will now also be shown
    • Access paths will only be shown on public constants since the perf gain from caching is more valuable than being able to see the access paths on protected/private consts depending on calling scope
  • Methods/Statics/Constants will be shown for class strings dumped at the top level

@jnvsor
Copy link
Member Author

jnvsor commented Sep 29, 2024

6.0-beta5:

  • Fixes for building under windows
  • Dynamic CLI size support on windows (Where tput available) (From @DRSDavidSoft)
  • RendererInterface no longer has to implement renderNothing
  • Small DateTime changes and tests

@DRSDavidSoft
Copy link
Contributor

Just noticed this, interesting changes for Kint 6!

  • "Open in new window" button has been removed. I for one never used it, and the code involved obfuscation and the likes to get around browser security measures. Basically it was ugly and could break at any time so I figured I'd remove it. If it actually got a lot of use and I get complaints here I can port it back in but I doubt it.

Sad to see this feature go away, I used it seldom on good old days when the front-end and back-end of an application lived in harmony together. I wasn't aware that the code relies on obfuscation to bypass browser pop-up window blocks, I mean this really shouldn't be required, as the developer certainly has the option to allow-list the domain they are working on. It was a cool handy feature.

I guess other methods are available. Also a cool feature would be to get a exported var_export() or json_encode() version of the dumped variable so that it could later be imported in another kint window. Or, you could provide a kint://var-data/... type of url, where clicking on it would open a registered Kint application written in JavaScript in another window. Just some ideas.

Full JS rewrite. Now we stop trying to be clever and just put it in 1 file and dump the whole thing on the first dump of both rich and plain renderers. It's a bit of extra bandwidth but 12kb isn't much when dumping a container from a typical framework is measured in mb.

Seems like a good re-write, I agree in the modern age of web development, 12KB isn't really much when the other aspects of the application goes into MB. Still, miss the quite handy and compact tool, but reality is we don't write apps like we used to do ten years ago.

kint-ide-link behavior removed. [....] It had custom behavior of sending an AJAX request if the link is in http or https protocol that seems to have been used for VERY old phpstorm versions. Nowadays you can just set a protocol link

Never used the http/https scheme for this, also I use VS Code as an IDE more than IntelliJ-based IDEs such as PhpStrom, which supported application link schemes from the get go.

BTW, On the CLI, Kint dumps the file path, which both the terminal (e.g. Windows Terminal) and VS Code will happily take me to the specified file an line number using some sort of keyboard combination (e.g. Alt-Click or Ctrl-Click)

In both cases (CLI and Web) this is pretty useful! 👍🏻

"undefined" is now "uninitialized" for php naming consistency
Nice change, "undefined" reminds me of JS while "uninitialized" is most definitely for PHP.

ToString, Binary, Mysqli, and DOMDocument plugins are now on by default
Oh, that's a great change as many devs like me tend to dump properties and vars that are relevant to these.

@DRSDavidSoft
Copy link
Contributor

DRSDavidSoft commented Sep 29, 2024

Some more thoughts regarding the theming:

  • I would appreciate an auto dark mode feature. This can be implemented via JS and would check the device preference or the meta tag such as the following:

    <meta name="color-scheme" content="dark light">

    This is awesome to be consistent with the application design and would be easier on the eyes.

  • A new refreshed color scheme for a better look would be nice, the original theme is looking a bit dated. I would be open to implement some tweaks and changes as well where required.

  • Fix RTL issue: Kint isn't supposed to render in the RTL (Right-to-left) mode. If the direction of page (or the parent element) is set to RTL, then Kint wouldn't display properly. I believe it would be better to force direction: ltr into the Kint themes.

  • IE support needs to be dropped, the extended support by Microsoft ended in 2022 and I don't believe any devs would use it nowadays, at least in combination with Kint. The compiled JS code is using things such as the spread operator, which I doubt is supported on IE. If this is the case, there is no need for things such as base64 encoding for the caret in the scss.

    Alternatively, you may be looking to support IE until 2029, which is the date that the backwards compatibility in Edge will also end.

  • Open in New Window can remain in the code base. All you need to do is to remove any kinds of hacks and workarounds that were previously needed. window.open() is a standard browser feature that is still used, it's not deprecated or considered bad practice.

    So, we're essentially requesting the browser to open a new window for us. It's the user's choice if this request is denied or accepted. We shouldn't rely on any kind of obfuscation, we simply made our request. Now it's the user's and navigator's responsibility to open the window; if it's blocked, it's the user's role to grant access to open the new window.

  • It appears that the docs has been reduced through the years. I believe more extensive documentation would be appreciated for customizing Kint to one's specific needs, without needing to go through the code or PHPDoc declarations.

@jnvsor
Copy link
Member Author

jnvsor commented Sep 29, 2024

Sad to see this feature go away

As discussed with HLeithner I ended up replacing it with a dynamic "Move to folder" button that gives you a larger viewing space without opening a new window context, which is the best of both worlds

miss the quite handy and compact tool

The old JS was 4 files totalling 13kb but it would try to cleverly only dump the ones needed so while the new JS is now 15k in practice that 15k is 30k if you dump with both plain and rich.

But dumping a symfony request is +170k, a container from a fresh symfony install is +4mb, and container from a fresh sylius/drupal install is ~80mb. A warm system with loads of services can easily reach into multiple GB of output (And then your browser is the performance bottleneck not the server)

So I'm really not worried about a few kb more JS

I would appreciate an auto dark mode feature

This would require dumping at least 2 themes on start - one for light mode and one for dark mode. Currently the themes aren't designed to be dynamically switchable, if you load two at once it'd be some weird blend of the two.

So you'd have to output two stylesheets and throw one away with JS. Is this a good idea?

A new refreshed color scheme for a better look would be nice, the original theme is looking a bit dated

Agreed. Unfortunately I have the artistic sense of a mole. (Blind and leaves a mess) I can implement a design or color scheme if you come up with one but don't ask me to come up with one myself :)

If this is well designed and using more modern css variables that can be changed browser side, we could figure out a way to roll auto dark mode into it, but I've never looked into that.

Could you start an issue and start thinking about new design stuff?

Fix RTL issue

Oh good point. I'll have to look into this. Let me open a new issue

IE support needs to be dropped

Way ahead of you. I'm just doing an out of the box esbuild now (It doesn't try to transpile to an older subset at all)

Open in New Window can remain in the code base [...] window.open() is a standard browser feature that is still used

It's not window.open that's the problem, it's inserting script and style tags into the newly opened window. And it's not just browsers either.

For instance the 5.1.1 code had to have a mktag function that just wrapped whatever you sent it in <> for no other reason than to dodge "Security" systems that freak out when they see html in JS

It appears that the docs has been reduced through the years

No, it's been expanded, it's just that kint 1.0 wasn't extensible at all and there have been a lot of changes made to improve that over the years that never got documentation.

@DRSDavidSoft
Copy link
Contributor

This would require dumping at least 2 themes on start - one for light mode and one for dark mode. Currently the themes aren't designed to be dynamically switchable, if you load two at once it'd be some weird blend of the two.

So you'd have to output two stylesheets and throw one away with JS. Is this a good idea?

I was actually thinking of loading one by default (which is also useful on non-JS enabled environments, like the developer console preview) then use JS to detect enabled dark mode and load that one.

But this isn't even needed. Instead of relying on two themes with different color schemes (e.g. aante-light and aante-dark, we can have an aante-auto (or even just aante) and handle the dark mode based on device preferences, entirely from CSS which is awesome because you don't need to use any kind of JS.

Using this:

@media (prefers-color-scheme: dark) {...}

Which means that in the SCSS, the default light mode is used. But upon the existence of prefers-color-scheme and its value being dark, then the color schemes can be overridden to a cool looking dark mode! A very neat trick that I tend to use in my projects.

So we have:

  • aante-dark: forced dark mode always
  • aante-light: forced dark mode always
  • aante-auto or just aante: automatic pick based on device preference (browser settings)

If you are going to drop IE support, this can be paired with css variables which means a truely awesome experience for applying customizations to the color schemes with minimal lines of stylesheets being added at all.

I also suggest creating a cool looking original-dark color scheme as well and applying this proposal on that too. I'd like to contribute to the color scheme for the dark mode too if possible.

Agreed. Unfortunately I have the artistic sense of a mole. (Blind and leaves a mess) I can implement a design or color scheme if you come up with one but don't ask me to come up with one myself :)

If this is well designed and using more modern css variables that can be changed browser side, we could figure out a way to roll auto dark mode into it, but I've never looked into that.

For sure, I would love to contribute some values for the new color scheme. Functionality and eye strain prevention are top priorities, and I would prefer a very modern and cool looking design. The original theme could either use more contrast and vibrant colors, or stay to pale colors (also known as pastel, which is easy on the eyes).

I just need some basic information about the layout and structure of the scss files, I can refactor to use CSS variables and then add dark mode into it without any worries.

Could you start an issue and start thinking about new design stuff?
#428

That's awesome. Let's discuss more about theming in there.

IE support needs to be dropped
Great to see IE go. It served us well in the early 2000s. Now we can refactor the code to remove all mention of it and remove all ugly code that was kept because of it. Which means the S/CSS development will once again be a joy, the same way that lack of transpilation is joyful. 😄 Exciting times.

For instance the 5.1.1 code had to have a mktag function that just wrapped whatever you sent it in <> for no other reason than to dodge "Security" systems that freak out when they see html in JS

Oh, I see, this is because Kint is rendering the content in the PHP side. You know, I was thinking of implementing a pure JS Kint app that is able to render the same thing as PHP, but from a serialized string. Wouldn't that be cool? 😉 Maybe in Kint 7 or the future. Imagine the possibilities: We can store a serialized string in the database during bug report/crash report (Laravel uses Symfony and provides such feature). Then later we would be able to see the dumps made and render it using Kint.

Currently I resort to ob_* buffer feature of PHP to capture the entire HTML output that is generated by Kint. As said, just an idea! 😄

there have been a lot of changes made to improve that over the years that never got documentation

It's never late to document the features that Kint provides. Also happy to contribute in that area, but I have no idea where to start. Fortunately, GitHub Copilot is superb at generating good documentation based on the code, so maybe we can start at that.

My colleagues hadn't even heard of Kint, one mentioned to me he had seen it but opted to use Symfony's dumper utility since it had more docs on especial use cases. He was blown away by the feature set that Kint provides. In my opinion we need to make sure people know what they're going to miss if they don't use Kint! 😄

@jnvsor
Copy link
Member Author

jnvsor commented Sep 30, 2024

You know, I was thinking of implementing a pure JS Kint app that is able to render the same thing as PHP, but from a serialized string

kint-js renderer used to be a thing but it was a simplified dump compared to rich.

I tried rewriting rich in vue for performance once. Turns out it's way less performant to add 10k dom elements from a virtual dom than to just set 10k preexisting elements display:block and let the browser reflow.

So I'm not sure if this'll be worth the effort but you're welcome to give it a try

We can store a serialized string in the database during bug report/crash report

Yeah you could already do that if you made your own renderer. It's even documented:

What the renderer does is somewhat irrelevant. It could print out text or it could print out HTML. It could store the dumped data in a database or email it to the ISS.

Currently I resort to ob_* buffer feature of PHP to capture the entire HTML output that is generated by Kint

$output = @d($var) or Kint::$return = true will do this

Fortunately, GitHub Copilot is superb at generating good documentation based on the code

Well clearly my documentation is lacking given the last few points but I question how good the quality of AI docs will be: Kint has a lot of weird stuff and recursion that it may not be great at handling.

I think the "Using kint as a tool" part of the docs is fine, it's "Using kint as a library" that gets people confused. I'm thinking I should take the "Improving Kint" and "Writing plugins" part of the documentation and put them into a subsection (named "API" perhaps?) where I can expand on internal docs.

@jnvsor
Copy link
Member Author

jnvsor commented Oct 12, 2024

6.0-beta6:

  • Mysqli is now parsed correctly in text modes
  • CSS forced ltr direction inside dumps
  • Array recursion checking is now done with ReflectionReference instead of a marker. This is safer since we don't run the risk of changing the user input and parser plugins don't have to call cleanArray to remove it
  • Added support for 8.4 async visibility
  • Split values and contexts. This is part 1 of a massive refactor of the Kint\Zval namespace. It breaks pretty much everything and is too complex to realistically split into smaller parts than this.
    • For library users: Bases passed into Kint->dumpAll should now be Kint\Zval\Context\BaseContext and otherwise it's pretty much the same
    • For plugin devs: Basically everything changed. New interfaces to implement, new output method (Just return, no reference out vars) different parseBegin/parseComplete methods, haltParse is gone instead return a Value to halt parse in begin... You're gonna have to read the code until the docs are up to date
    • Biggest improvement is memory use where you'll get roughly 10% less memory used than earlier versions despite adding info to store like hooks and async visibility (We're no longer storing all that stuff on values in arrays for instance)

Because of the sheer engorged mass of this refactor I'm not going to bother updating the docs just yet - it'll change more before it's done. Next steps:

  1. Remove value representations and have canonical values returned by method. This means we can just store the literal value of scalars and strings on the Value and use the representations exclusively for tabs (And not store anything for resources by default)
  2. Base representation will be split into StringRepresentation and ContainerRepresentation - the others for int/float/etc. will no longer be needed since the Value can store that directly. ContainerRepresentation will always store Value[] to simplify renderer logic

@DRSDavidSoft
Copy link
Contributor

Also the CSS rewrite which I'll be submitting as a PR soon to support auto dark more and some tweaks - sorry been a bit busy at work, but super excited to include this as well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants