In this update
Welcome to the November 2023 edition of “What’s New in RokuCommunity.” Please consider subscribing to stay up to date with what’s happening in RokuCommunity.
This month we ran a trial of auto-enabling the debug protocol by default. We added several much-needed performance improvements in the brighterscript v0.66 alphas. We fixed a few bugs in the brs emulator, improved our telemetry tracking, added a few improvements to the dev experience for our RokuCommunity contributors, and a lot more! As always, many thanks to all who have worked so hard and contributed this month!
There are many updates in this version that we hope you’ll like, some of the key highlights include:
create-package
label build script to help contributors test pull requestsThe RokuCommunity projects are maintained by a relatively small group of developers (mostly volunteers), and we have a growing list of of unresolved issues. We need your help! There are many different ways you can contribute. Whether it’s addressing bugs, improving documentation, introducing new features, or simply helping us manage our expanding list of GitHub issues, your involvement would be greatly appreciated. We are more than happy to guide you in finding the most suitable contribution method that aligns with your interests. To learn more about how you can contribute, feel free to reach out to us on Slack, or explore the existing GitHub issues:
In this section, we highlight a specific issue where we could benefit from the community’s assistance in finding a solution. These problems are generally straightforward to address, and serve as an excellent opportunity to become acquainted with the RokuCommunity codebases.
This month, we’d like to draw attention to vscode-brightscript-language#409. A rather strange issue that Roku developers encounter is when the Roku device stops allowing developers to sideload channels. Sometimes this is due to the Roku device requiring you to manually “check for updates”. It’s curious why the Roku won’t just do this itself, but alas, it’s not something in our power to fix. However, what we can do is properly detect that this is the reason why the sideload failed. That’s what vscode-brightscript-language#409 is asking to do.
We’d like to detect when the sideload fails as a result of the “Failed to check for sofware update” issue, and then show a modal to the developer explaining why the sideload failed.
If you’re interested in working on this feature, please comment on the github issue or reach out to us on Slack
We added a new data point to our telemetry tracking. We now track Roku OS version during the startDebugSession
telemetry event. This allows us to better understand what Roku OS versions our developers are actively using so we can better plan our roadmap for future features. We are very intentional about what data we collect. You can review all of our telemetry tracking data points in this file.
Here’s a chart showing the OS version across all debug sessions for a month:
There’s now a warning that will appear when starting a debug session against a Roku device that doesn’t have developer mode enabled. Previously the debug session would silently fail, requiring you to dig through the output logs to figure out what went wrong.
We ran a test this month to try out the debug protocol to a large portion of our user base. The test ran for about 4 weeks to see what issues were uncovered. We were hoping that if the test went smoothly then we’d leave this feature enabled indefinitely. However, we discovered several issues as a result of this test, so the default debugger has been restored to telnet.
Here’s how the test worked:
Set enableDebugProtocol
to true
for any debug session started on a device running RokuOS 12.5 or greater that didn’t explicitly define enableDebugProtocol
. We notified the user that we enabled the protocol, but we still gave them an option for using telnet instead. We hoped that most users would still choose to test out the debug protocol because it will become the default debug mode some time in the future.
Here’s what the popups looked like:
Then after 2 clicks of the “Use telnet” button, we switch to this so the user can hide the popup for 12 hours.
here’s the “report issue” dialog:
device-info
request on every launch, if the device can’t be found, vscode would appear to do nothing for up to 2.5 minutes. Now it only waits about 5 seconds. (Read more about this issue here)After a month of testing, we decided to turn this feature back off. The debug protocol is still available by setting enableDebugProtocol: true
in your launch.json. We hope to fix these issues and run another test at some point in the new year, once we are confident we’ve addressed most of the pain points. We are still confident that the debug protocol be the most efficient and effective way to debug Roku apps due to its stability and dependability, but we need to make sure our implementation maintains feature parity with the telnet debugger.
As part of the telemetry tracking update, we now do a device-info
request at the start of every launch request, in order to discover certain features of your device (is dev mode enabled, what OS is the device running, etc). However, we forgot to set a reasonable timeout on that request. It was previously set to 2.5 minutes. We’ve now adjusted that to a much more sensible 5 seconds.
We now show a statusbar loading animation while this query is running. In most cases, this request should only take 20-100ms. If it takes longer, that’s typically indicative of a much bigger issue like the device being offline or inaccessible on the network.
In the devices view in vscode, you can now click on the new View Registry
button under any device. After choosing your app from the list, it will then open the registry ECP response in your web browser. While we show all channels on the device in the list, you can only access the dev app and channels matching the keyed device.
Here’s an example of this in action:
For projects that leverage the template string feature of BrighterScript, we’ve added language/editor support for backticks (templatestrings) for autoClosingPairs and autoSurroundingPairs. So you can finally get editor help like this:
When starting a debug session, we delete any dev channel right before sideloading your app to the Roku device. Sometimes that delete call would fail and then crash that debug session. We’re not entirely sure why the delete fails, but in most cases this is recoverable, so now we try/catch the delete and continue with the rest of the launch flow. This should hopefully reduce the number of times the vscode extension stops a debug session for seemingly no reason.
We fixed a small typo in the “you’re using the debug protocol” message. Before:
Protocol Version 3.0.0 has not been tested and my not work as intended.
Please open any issues you have with this version to https://github.com/rokucommunity/roku-debug/issues
After
Protocol Version 3.0.0 has not been tested and may not work as intended.
Please open any issues you have with this version to https://github.com/rokucommunity/roku-debug/issues
Thanks @jeanbenitezu (Jean Benitez)!
During a debug protocol debug session, often times the debug session just shuts down with no explanation. We found an issue related to compile errors where the debug protocol sometimes shuts down the control port before we’ve had a chance to receive the compile error events. We’ve fixed this issue in two ways:
With this fix in place, you can once again see all your wonderful syntax errors in bright red highlights!
We fixed a small precedence issue when parsing unary expressions related to negative expressions like -x
or -someValue
. You can check out brighterscript#938 for more information.
We fixed a transpilation bug when using enums directly (eg. with no namespace prefix) inside a namespace. It was especially prevalent in classes.
namespace MyNS
class HasEnumKlass
enumValue = MyEnum.A
end class
enum MyEnum
A = "A"
B = "B"
end enum
end namespace
was being transpiled to (notice the MyEnum.A
):
function __MyNS_HasEnumKlass_builder()
instance = {}
instance.new = sub()
m.enumValue = MyEnum.A
end sub
return instance
end function
function MyNS_HasEnumKlass()
instance = __MyNS_HasEnumKlass_builder()
instance.new()
return instance
end function
We’ve now fixed it, so it will properly transpile to:
function __MyNS_HasEnumKlass_builder()
instance = {}
instance.new = sub()
m.enumValue = "A"
end sub
return instance
end function
function MyNS_HasEnumKlass()
instance = __MyNS_HasEnumKlass_builder()
instance.new()
return instance
end function
We’ve added logic to the brs
emulator for optional chaining. If you’re leveraging this awesome project for off-device brs runtime, you can now safely use optional chaining in your brs code.
sub test()
print m?.optional?.chaining?.works ' yay!
end sub
We fixed a bug with how chained method calls were interpreted. They were incorrectly re-evaluating each item in the chain multiple times, when they should have been evaluated exactly once.
? CreateObject("roTimeSpan").TotalSeconds().ToStr().Trim()
Would result in .TotalSeconds()
being evaluated/called 4 times.
It’s now been fixed to only evaluate once, which aligns us with Roku’s brs runtime.
We fixed a parsing bug that would apply the wrong negative sign precedence, which would result in math errors.
print -1000 +1000
This will now apply the -
and +
in the correct precedence and the result will be 0
.
Roku’s device-info
ECP endpoint is extremely useful for determining what functionality a given Roku device can support. We use it across many RokuCommunity projects, such as the VSCode extension, roku-debug, and roku-deploy. We recently discovered that each of those projects had their own implementation of fetching device-info
. So to reduce code duplication and centralize our logic, we’ve enhanced the implementation in roku-deploy by adding an enhance
option that returns the properties in camelCase
instead of kebab-case
and converts boolean strings to booleans and number strings to numbers. This opt-in flag retains backwards compatibility by adding an overloaded signature that is off by default.
Here’s how you can leverage this functionality:
import { rokuDeploy } from 'roku-deploy';
const deviceInfo = rokuDeploy.getDeviceInfo({
host: '192.168.1.33',
enhance
});
console.log(deviceInfo.serialNumber); // yay no more kebab-case keys!
console.log(deviceInfo.eveloperEnabled); //prints `true` (as boolean, not string)
We found (and fixed) a few bug in the roku-deploy zip upload response parsing. There were several additional errors that could be scraped from the response which would provide much better information about why certain issues were occurring. We now properly parse those errors and include them as part of any emitted error. Check out roku-deploy@127 for more information.
We fixed a bug in roku-deploy where we weren’t waiting for the downloaded file stream to close before resolving the file path promise. When used in CI environments, this could actually cause the CI job to fail because sometimes the file wasn’t finished downloading, which could trigger “file not found” errors if the CI moved ahead too quickly.
We made a lot of great progress again this month on the latest brighterscript v0.66 alpha releases. Here are some of the highlights:
We added the ifDraw2d
items to the roRegion
interface, which should result in much better completions and validations when interacting with those items.
We fixed some performance problems when computing completions. Since completions are one of the most time-sensitive operations, this was a huge win! Here’s how the flow was changed:
Previously:
for each scope file is in
on file text completion,
for each scope the file is in
get all symbols from entire symbol table
Now:
on file text completion,
get symbols local to the completion position
for each scope the file was in
get symbols available at scope level
get symbols based on namespace inclusion
get the symbols from global scope
remove duplicates of same completion across different projects
We’ve finally added the ability to mark interface (and class) properties as optional
. These properties can be omitted from interfaces without fear of validation errors when they’re missing (i.e. the entire point of optional properties…).
We added fixes for the “go to definition” logic so that it finds classes and interfaces.
Here’s it working in action!
The v0.66 alphas are known to be slower than the mainline release. Much of this is attributed to the significant amount of additional validation being performed. This month we focused heavily on finding performance improvements to try and gain back some of that lost speed. We found several ways to carve out some more performance:
ifDraw2d,DrawScaledObject
overloadScopeValidator.iterateFileExpressions
to do work on an AST Walknpm run benchmark -- --targets validate
:
Current release-0.66:
validate@local ----------- 8.252 ops/sec
validate@0.65.8 --------- 104.338 ops/sec
Implementing algorithm above:
validate@local ---------- 21.253 ops/sec
validate@0.65.8 --------- 105.035 ops/sec
We also found some significant performance improvements during the program validation cycle. Let us know if you are still seeing performance issues while validation your projects. Check out the benchmark results (higher is better):
validate@local --------- 271.514 ops/sec
validate@0.65.10 --------- 101.219 ops/sec
⚡ Huge improvement to validation times! ⚡
How it works:
We found another area for performance improvement by caching the range and position objects since they’re immutable. This helps reduce memory footprint and garbage collection churn. Also after a range has been created at least once, it should theoretically cost less CPU cycles since we just look it up from the cache instead of building a new one.
For a large private project:
location cache: DISABLED
build: (8s191.958ms) (7s967.413ms) (8s222.454ms) (8s035.043ms) | (avg: 8.104217seconds)
watch: (8s103.313ms) (8s104.476ms) (8s200.875ms) (8s100.466ms) | (avg: 8.127283seconds)
location cache: ENABLED
build: (7s965.510ms) (7s977.796ms) (8s167.780ms) (7s960.608ms) (avg: 7.7679235seconds)
watch: (7s873.529ms) (7s967.520ms) (8s018.557ms) (8s091.832ms) (avg: 7.9878595seconds)
For the same project, we end up caching a ton of ranges and positions. As the app lives in watch mode for a while, I would expect more and more of those locations to get recycled:
cold boot:
Ranges: 254,551 cached 193,085 not cached
Positions: 418,227 cached 10,588 not cached
after 4 watch validations:
Ranges: 392,111 cached 163,335 not cached
Positions: 418,227 cached 10,588 not cached
If there was a class field that used a constructor, the constructor was not namespaced correctly in the transpilation. This fixes that issue.
namespace MyNS
class KlassOne
other = new KlassTwo()
end class
class KlassTwo
end class
end namespace
Now properly transpiles to:
unction __MyNS_KlassOne_builder()
instance = {}
instance.new = sub()
m.other = MyNS_KlassTwo() 'This was the issue before, it used to transpile to `KlassTwo()`
end sub
return instance
end function
function MyNS_KlassOne()
instance = __MyNS_KlassOne_builder()
instance.new()
return instance
end function
function __MyNS_KlassTwo_builder()
instance = {}
instance.new = sub()
end sub
return instance
end function
function MyNS_KlassTwo()
instance = __MyNS_KlassTwo_builder()
instance.new()
return instance
end function
not
keywordWe fixed a bug in the brighterscript parser related to how the not
keyword is interpreted.
function stringHasStuff(myStr as string) as boolean
return not myStr = ""
end function
The parser treats this as (not myStr) = ""
instead of how Roku treats it: not (myStr = "")
As a result, here’s the fix: Before:
not myString = ""` -> `BinaryExpression<=>(UnaryExpression<not>(myString), "")
Now:
not myString = ""` -> `UnaryExpression<not>(BinaryExpression<=>(myString, ""))
This might not mean much to you, but just know that your code is now being interpreted (and transpiled) more accurately now.
We’ve added a new github label called create-package
. This will leverage GitHub actions to build one-off npm package releases for any git branch. This makes it very easy to test a pull request without needing to clone the repo or do npm link shenanigans. Simply set a create-package
tag on the PR, then the bot will comment when the build is ready to test.
This is available in:
Here’s what the comment on PRs looks like:
noUnusedLocals
tsconfig flag in vscode-brightscript-languageWe’ve enabled the noUnusedLocals
flag in the tsconfig in vscode-brightscript-language and cleaned up all the warnings that introduced. This means that you’ll now see typescript warnings and errors for unused variables. This also applies to unused imports.
watch-all
for alternate cloned dir nameContributors often follow this guide for setting up their RokuCommunity development environment. We fixed a few bugs in d816cce related to how the watch-all
command works when you cloned vscode-brightscript-language
to a folder not named vscode-brightscript-language
. So you probably won’t notice, but it works better now.
In the spirit of fixing problems with watch-all
, we also fixed the problem matcher in the watch-all
task when running the RokuCommunity workspace. This is fixed by emitting absolute paths instead of relative paths, which then work for both the workspace and individual folders. Just like the last item, this is just a small quality of life thing.
For contributors of the vscode-brightscript-language, we’ve created a set of helper functions that reduce duplication when prompting for common user input (such as host, password, etc). This first iteration introduces a promptForHost
method into a UserInputManager
class so we can start centralizing our user input flows and sharing them to unify the experience across the extension.
We discovered that several different places across the RokuCommunity projects that all ran similar device-info
requests. We have eliminated this duplication by leveraging the getDeviceInfo()
call from roku-deploy. In the future, all device-info calls should be handled by using that singular interface.
Last but certainly not least, a big Thank You to the following people who contributed this month:
Contributions to vscode-brightscript-language:
noUnusedLocals
tsconfig flag (PR #515)Contributions to brighterscript:
not
keyword (PR #932)providedSymbols
and requiredSymbols
(PR #944)test-related-projects
on release since it already ran on build (157fc2ee)Contributions to roku-deploy:
Contributions to roku-debug:
Contributions to brs:
Legal notice
The views and opinions expressed in this website and all of its pages are those from within our open source community and do not represent the views or positions of Roku, Inc. or any entities they represent.
Designed with @arturocuya, powered by Astro
by