Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

What's the best setup for building Roll20 scripts out of multiple Typescript files?

1613316378

Edited 1613334729
EDIT to put some information I gathered at the top for future readers: For tsconfig.json, I used target == "ES2019", and module == "None". For Webpack, I used globalObject == "this", and libraryTarget == "umd". I think a roll20.d.ts file should declare all of roll20's names using "declare global { }". Individual Typescript files should not import anything to account for this file, but should just use the global declarations. It seems like the roll20.d.ts file can then be included like any other source file. It was really hard to find information about this exact situation online (i.e. the situation where the runtime environment provides global symbols). I got this done with one monolithic tsconfig.json that built everything; I should have done it that way first! I separated Typescript compilation and Webpack packing into two different steps, by telling Webpack to build using the Javascript outputs instead of the Typescript files. This was simpler than fighting with ts-loader errors. I think that Webpack is including its own module setup when the Javascript code doesn't have one. Fortunately this doesn't make Roll20 complain and script loading is not noticeably slower than a typical script. Original question: I'm looking for a way to set up a Typescript project, optionally with other tools like Webpack, to build multiple Typescript source files in multiple directories into a single script that I can copy-paste into the Roll20 editor. I'm a complete novice to front-end development and this is my first Javascript and  my first Typescript project. EDIT: I think that was a mis-statement in terms of the question context. There are two problems that crop up: As far as I can see, Roll20 doesn't support any of the typical module systems, so I need configs for Typescript and the surrounding tools that don't produce *any* module code. (Is there a module system that Roll20 supports, or at least that it will ignore?) When an output script is broken, I typically get a SyntaxError with no context of any kind (e.g. " SyntaxError: Unexpected token '.' "). So I really don't have any way to fix it other than blindly changing configs and hoping for the best. Ideas? Thanks!
1613316852
timmaugh
Forum Champion
API Scripter
I don't have experience setting up a Typescript library so I can't help directly on that, but in the Roll20 environment, as I understand it, you have access to Node.js, vanilla JS, and the underscore library. I've pinged Aaron to see if he can offer more insight. In the meantime, I wonder if an online typescript =&gt; javascript converter would help...? <a href="https://extendsclass.com/typescript-to-javascript.html" rel="nofollow">https://extendsclass.com/typescript-to-javascript.html</a>
1613319132

Edited 1613319185
The Aaron
Roll20 Production Team
API Scripter
Just a correction on the above. The API runs on Node, but there isn't any of Node's environment exposed to the API. All code is executed in a Sandbox, and only has access to Javascript (around ES2019), the Underscore.js library, and Roll20's interface.&nbsp; I have to say that tackling TypeScript, Webpack, and the API all in one go as a first timer seems like a bit much. I'd suggest starting with just writing some vanilla Javascript API scripts, then convert those to their TypeScript equivalents, then subdivide that and get wrbpack working.&nbsp;
1613319546

Edited 1613319741
I appreciate the responses. I'm not a first-timer to development, just to Typescript and Webpack and the ecosystem. The build systems all seem pretty weird compared to what you'd expect out of Java, or a typical C++ build environment. I didn't know what version of Javascript to target, so I will check what the Typescript projects are set to generate.
1613320705

Edited 1613322314
Update: After Aaron's post, I changed the Javascript target version of my tsconfig from "esnext" to "es2019" and got a different syntax error (the runtime didn't know what the symbol "self" was). I dug around and found that Webpack was assuming a global variable "self" because it assumed an environment with window.self etc. available. So I switched it to a global variable of my choice and added a var X = {}; for it. At that point I got a "cannot find module" error, and since my packed script has require() statements, I am thinking that require() is available, but just doesn't do anything. So there's a little chunk of Node.js that is exposed. I may be able to do something with module setup to fix it. EDIT: I also have the option of using Typescript namespaces. I switched away from them because I thought Webpack was getting confused by them.
1613323095
timmaugh
Forum Champion
API Scripter
A couple more notes on the environment... ...it isn't true "front-end" development as API scripts won't have access to the window, or any of the DOM. All of the exposed functionality is to the firebase db collating all of the changes that happen in the game, behind the scenes. There is no ability to require(), as you're working in a sandbox with a limited interface. ...all of the scripts are compiled into one long file, making error chasing sometimes difficult. See Aaron's method for helping to track those down. ...if this is your first foray into javascript (coming from a more formal language), you should investigate hoisting, the global namespace, and the revealing module pattern . Aaron compiled some other helpful links in this post . But, also, welcome to the wonderful world of scripting!
I think I understated my experience too much, sorry. I've been working on this code for months in Javascript, and I think it was the last week or so that I rewrote it in Typescript after work. It's all of the surrounding infrastructure (building, deployment, Web apps, the window, useful npm libraries) that I have not worked with much. Roll20 supports classes and #-privacy, so I've been using that in place of Revealing Module. (I think the community here would benefit *a lot* from using the class support, since Revealing Module adds a lot of weird boilerplate.) My idea was to either stub out require() to "do the right thing" without formal Node.js support, or to find something in Node.js that allows you to dynamically add code as a loadable module (i.e. sort of like a Java class loader). Those are pretty hacky and I am probably going back to Typescript namespaces. I have not strongly investigated hoisting, I've been limiting myself to use after declaration. That kind of thing is one reason I'm converting my stuff to Typescript.
I've gotten it to work. Thanks to Aaron for pointing out the importance of targeting the right JS version; once I fixed that Roll20's error output was much easier to understand. Changes I made, which I'll record for the benefit of others: For tsconfig.json, I used target == "ES2019", and module == "None". For Webpack, I used globalObject == "this", and libraryTarget == "umd". I think a roll20.d.ts file should declare all of roll20's names using "declare global { }". Individual Typescript files should not import anything to account for this file, but should just use the global declarations. It seems like the roll20.d.ts file can then be included like any other source file. It was really hard to find information about this exact situation online (i.e. the situation where the runtime environment provides global symbols). I got this done with one monolithic tsconfig.json that built everything; I should have done it that way first! I separated Typescript compilation and Webpack packing into two different steps, by telling Webpack to build using the Javascript outputs instead of the Typescript files. This was simpler than fighting with ts-loader errors. I think that Webpack is including its own module setup when the Javascript code doesn't have one. Fortunately this doesn't make Roll20 complain and script loading is not noticeably slower than a typical script. Webpack is putting a lot of symbols into the global namespace; I haven't figured out how to avoid that.
1613329812
timmaugh
Forum Champion
API Scripter
I had not realized R20 had implemented the # privacy declaration. I thought I'd just tested that a month or so ago. Perhaps I only dreamed it.
timmaugh said: I had not realized R20 had implemented the # privacy declaration. I thought I'd just tested that a month or so ago. Perhaps I only dreamed it. After your post I got nervous of my own memories and decided to test it: class TestClass { #nameString = "test_class_debug_string"; #intValue = 0; returnDebugString() { return this.#nameString + this.#intValue; } } log("new TestClass().returnDebugString() =&gt; " + new TestClass().returnDebugString()); log("new TestClass().#intValue) =&gt; " + new TestClass().#intValue); with the result SyntaxError: Private field '#intValue' must be declared in an enclosing class I tried again with that line commented: class TestClass { #nameString = "test_class_debug_string"; #intValue = 0; returnDebugString() { return this.#nameString + this.#intValue; } } log("new TestClass().returnDebugString() =&gt; " + new TestClass().returnDebugString()); //log("new TestClass().#intValue) =&gt; " + new TestClass().#intValue); and got a positive result: "new TestClass().returnDebugString() =&gt; test_class_debug_string0" This makes me think that the Revealing Module pattern is obsolete even for Roll20.