Teacher's Guide: Libraries
Overview
This lesson builds upon previous lessons that focused on I/O, to include loading and executing 3rd-party JavaScript programs. The lesson introduces students to code repositories (in particular, npmjs) and content delivery networks (CDNs), and to the use of application programming interfaces (APIs).
More about the lesson
This lesson is a straightforward extension of The I in I/O lesson, both conceptually and practically. In this lesson, the focus is on loading scripts rather than other types of content. On the practical side, this lesson instructs students to use the $.getScript
function (alias for jQuery.getScript
) rather than the Pencil Code load
function. load
will in fact sometimes both load and execute scripts. However, it does not do this reliably. Use of $.getScript
ensures that the source-file code is executed.
As with other I/O functions such as load
and save
, $.getScript
functions asynchronously. Thus, as the lesson notes, it is generally easiest to make calls to $.getScript
in conjunction with await
/defer
. In the simplest case, execute a script located at src
with the statement
await $.getScript(src, defer())
As described in the Notes to the I/O lessons, an alternative to using await
/defer
is to manage the asynchronous processes using continuation passing style. In this approach, we pass all code that should be executed subsequent to the load as a callback. The syntax for calling the script located path src
, to be followed by a callback cb
, is: $.getScript(src, cb)
.
The code loaded by $.getScript
is executed immedately. Typically, however, nothing will appear to happen. This is because third-party scripts are usually designed to provide resources that we can incorporate into our own scripts at the time of our choosing. The functions and other resources through which we access functionality of a library are its Application Programming Interface (API). As the lesson notes, details about these resources, including instructions and examples, are typically available on the site that hosts the script (such as npmjs) or on a related website.
Finding Libraries
The lesson provides a handful of example third-party scripts. Some tend to the whimsical (for example, Elevator and FartScroll); others can provide simple solutions to common, but potentially complicated, coding tasks (Underscore.js); and still others offer some other useful feature (Granim, ChartJS).
There are thousands of libraries out there, many of them available through npm. npm is the world's largest Software Registry (i.e., collection of libraries). The name npm (Node Package Manager) stems from when npm first was created as a package manager for Node.js, but it has since expanded beyond that.
The question isn't whether there are useful packages out there, but how do we find some that are of particular value to us? Arguably, the best way to find a useful or fun library is through word-of-mouth. Ask your coding peers for ideas, and, if you find a good one, share with them! As always, however, a google search can go a long way, specificially when you are looking for particular features. Two additional useful resources:
- javascripting.com: the definitive source of the best JavaScript libraries, frameworks, and plugins. This site organizes scripts into categories, which facilitates a more directed exploration. It also includes a useful search feature.
- Awesome Javascript: self-described as "A collection of awesome browser-side JavaScript libraries, resources and shiny things." It is well-organized by content type. And if that's not enough, it even includes links to "Other Awesome Lists"!
Content Delivery Networks (CDN)
A content delivery network (CDN) refers to a geographically distributed group of servers which work together to provide fast delivery of Internet content. Because they are distributed, CDNs are typically are closer to the end user, and thus transmission times are reduced. For commonly used scripts (such as jQuery), the script from the CDN source is also likely to be already cached (that is, stored locally on the user's browser), obviating the need to download again, thereby saving time. Additionally, by offloading some file downloads to the CDN, traffic on the host server is reduced, also improving response times. (This article provides more details on the benefits and functioning of CDNs)
CDNs exist to provide various types of internet content, ranging from HTML files to video. Our interest is specifically in JavaScript libraries. Tech giants such as Google and Microsoft operate CDNs for JavaScript, but they tend to host only a small number of files. For example, Google's JavaScript CDN, Google Hosted Libraries, had less then 20 listings as of this writing (January 2023). (Though included in these are two we have interacted with already, jQuery (source code) and Web Font Loader (source code), the latter of which was explored in the additional activities in the Notes to the Calling All $(".turtle")s! lesson.
For files that don't make the cut at Google, etc., there are a variety of other CDNs, several of which specialize in hosting JavaScript libraries. One of the leading JavaScript CDNs is CloudFare, which hosts the ChartJS and Chroma scripts described in these notes. A particularly useful CDN for JavaScript is the open-source JSDelivr, which is free, fast and reliable. JSDelivr facilitates accessing code from the public code repository npm (as well as from the hosting and collaboration site GitHub—though finished projects there are typically posted to npm). For any package on npm, simply create a link to JSDelivr as described on its website. The simplest case is simply to append the npm package name to the path https://cdn.jsdelivr.net/npm/, e.g.,
https://cdn.jsdelivr.net/npm/cowsay
or
https://cdn.jsdelivr.net/npm/confetti
Notes to activities
The biggest challenge in working with third-part scripts is for students to pay adequate attention to the details of each package's API.
A complicating factor of working with third-part scripts is that API examples are typically presented using JavaScript contained in <script> tags which are in turn embedded in the headers of HTML documents. When they first get started with examples, students can (and should) simply copy over such programs into Pencil Code files with an .html extension, and run them to verify that the example works. (The HTML will render automatically, but you have to press the Pencil Code play button to invoke the scripts.) Then they will need to write a CoffeeScript version, as the goal here is for students to work with the CoffeeScript tools introduced in this and previous lessons. Aside from translating the JavaScript to CoffeeScript, they will also need to replace <script> tags with calls to $.getScript
. This can get tricky at times, depending on the API, as in the case of the additional exercise for Google Charts. As always, students can peek in the source code of solutions on hacker.pencilcode.net for clues.
Additional activities
SoundCloud: play songs from SoundCloud's extensive library using their Widget API. Unless you have an account, you only get access to a subset of their songs, but if you did you should be able to find something you like.
GoogleCharts: Google offeres a wide variety of charting tools, ranging from standard presentation graphs (line graph, bar plot, etc.) to GeoCharts and Maps. Give one or both of these latter two options a try, such as coding a WorldMap. Note that for some of the features of these packages, you will need a mapsApiKey. Instructions for obtaining such a key are provided in the API. But don't get bogged down in those technicalities before working through a more basic chart first.
- Add additional color-manipulation tools using jQueryColor. For example, make a FadingBackground program that cycles through different background colors.
- Create custom, interactive maps using Leaflet, which boasts being the leading open-source JavaScript library for mobile-friendly interactive maps. Consider making a map of your DailyCommute. The example uses a fixed array of locations to plot my route. Improve upon this using the interactive features of the program (i.e., events!), to allow a user to click on points on the map to generate an array of points to document their own commute. Use I/O features to make a permanent record of the user's entry.
Beyond the lesson
load
, $.getScript
, and $.ajax
The Pencil Code load
function and $.getScript
are both built on calls to jQuery.ajax
(i.e., $.ajax
). This section aims to describe the differences between these resources.
load
is essentially an alias for a call to $.ajax
. The reason to use load
for input of non-script files has to do with features of the Pencil Code server. For files stored on the Pencil Code server, load
converts the file path to include the string /load/ rather than /edit/ or /home/. For files not stored on the Pencil Code server, load
prepends /proxy/ to the source file's URL, so that when the actual call to $.ajax
is executed, the server takes the necessary steps to work around the same origin policy.
Simple calls to $.ajax
(and likewise load
) will execute the contents of the file if it can identify it as a script. Contrary to what one might expect, the file extension (e.g., .js) does not affect this result. Rather, jQuery attempts to detect whether it is a script based on the MIME type of the file, which is included in the file's metatdata. (MIME types were described in the Notes to the Input/Output Lessons.) If the MIME type is "application/javascript" (or the deprecated but still prevalent "text/javascript), jQuery executes the code upon loading it. Thus, simple calls to $.ajax
(and likewise load
) may successfully run scripts, but at times they will fail.
$.getScript
is also an alias for jQuery.ajax
, but it also explicitly inludes the option dataType:"script"
. This ensures that the script gets executed regardless of the metadata. A call to await $.getScript, defer()
(illustrated in this script) is equivalent to:
await $.ajax({ url:filePath dataType: "script" success: defer() })
In closing, note that the callback to $.getScript
(and to $.ajax
) can accept three arguments. These provide access to the source script, a string representing the status of the function call (e.g., when all goes well, "success"), and the jQuery XMLHttpRequest object. Students won't typically need access to these features, though they can be useful for debugging purposes. When using await
/defer
, pass three arguments to the defer
function to gain access:
await $.getScript(url, defer(script, textStatus, jqXHR)) see script see textStatus see jqXHR
Pencil Code loadscript
function
Yet another, simple-to-us alternative is the Pencil Code loadscript
function. Except when reading in files with extensions .cs
or .coffee
, loadscript
is an alias for $.getScript
. For the exception cases, loadscript
invokes CoffeeScript.load
, which compiles and then runs the designated script. Loading, compiling, and executing CoffeeScript files is the topic of the next lesson, Script Recycling!.
StyleSheets
CSS (Cascading Style Sheets) is used to style text and manipulate the layout of components on web pages. It can be used to alter the font, color, size, and spacing of content, to split pages into multiple columns, and even adding animations and other decorative features.
One of the advantages of CSS is that, once created, a style sheet can be referenced from multiple files. This means that, just as we can incorporate third-party scripts into our programs, we can also make use of third party style sheets.
External style sheets are normally declared within the <head> element of a web page. By default, styles sheets are loaded synchronously. That is, they halt all page rendering while the CSS is downloaded and parsed. Though this can result in page delays, it ensures that subseqent HTML page elements render correctly.
It is of course possible to add stylesheets programmatically, using JavaScript. Do this by appending a <link> element to the document's HTML header:
url="//fonts.googleapis.com/css?family=Berkshire+Swash" $('head').append('<link rel="stylesheet" href=' + url + '/>')
The one drawback to loading CSS via JavaScript is that the sheets do not block. In the case of fonts, this means that the fonts sometimes do not render the first time you load the page. Thankfully, however, the CSS files get cached (saved locally in your browser), so subsequent loads should work correctly.
What can go wrong
The benefit of using the lesson's approach to load a script is that it is fairly simple. The drawback is that when a load fails, we typically receive neither a notification nor information about the action. Execution details for calls to $.getScript
can be gained via the callback, by passing additional arguments. As noted above in the Beyond the Lesson section of these notes, a second and third argument to the callback provides access to a text string which reports success or failure, and access to a jQuery XMLHttpRequest object that provides an abundance of execution details.
If loading a library synchronously, the syntax is:
cb = (data, status, jqxhr) -> see "1) ", data see "2) ", status see "3) ", jqXHR $.getScript src, cb
The corresponding asynchronous call is:
await $.getScript(url, defer(script, status, jqXHR)) see "1) ", script see "2) ", status see "3) " jqXHR
That said, the most common error for this lesson is misspecifying the path of the source script. Thus, students may prefer to simply double-check their typing and skip this extra work!
Pedagogy/Technicalities
HTML <head>, <script>, and <link> tags
There is, admittedly, an easier way to load third party scripts, which is in fact the "normal" way to load third-party scripts. The technique is reference the script in a <script> tag in the HTML file's header. In the Pencil Code environment, we have not made much use of plain HTML, but we can easily add an associate HTML document to our programs by selecting the HTML button from the dropdown that pops up when you click the gear on the top right of the editor's code pane.
The biggest advantage of using a <script> tag is that, by default, JavaScript execution of such scripts is synchronous. This means that once a script tag is encountered, no other content can be loaded until the script it references has been downloaded, parsed, and executed. (All scripts which are loaded after DOM is ready are loaded asynchronously; this is why we need to use either Continuation Passing Style or await
/defer
when using $.getScript
.)
This lesson has emphasized executing third-party scripts using $.getScript
because it segues well to the next lesson, Script Recycling!, in which students will code their own reusable code repositories. Because students will code in CoffeeScript, we cannot invoke students' external scripts directly in a <script> tag. Rather, we would need to first compile it and save it as a JavaScript file. While this is certainly doable, this curriculum has opted to rely on the route of calling CoffeeScript.load, which works analogously to $.getScript
. Additionally, and arguably more importantly, asynchronous processes are a perennial stumbling block for coders. The additional practice students get working around these issues in this lesson is a valuable investment in their coding competency.
In conclusion, however, a strong case could be made for either approach. Arguably, from both a pedagogical and practical standpoint, the best approach to executing third-party scripts is to intoduce students to both aforementioned approaches.