This minimal project can be used as a starting point to build a progressive web application (PWA). This particular project
To keep this project small and avoid tooling that can be confusing for someone starting out with web apps, it forgoes a lot of nice-to-have features such as
There is currently no data associated with this application. You have two options. If you have previously saved a data file, restore it by specifying the file in the Restore section. Otherwise, if you want to load a small sample data set, click the button in the Load Sample Data section.
Restoring a file is a two-step process. First, select the file and then click Restore Project.
Click the following button to initialize the program with a small sample project. You will be able to modify the data and save it for later reuse.
This project demonstrates basic components of a progressive web app (PWA). It uses a rather opinionated approach in which each application page is put into its own div block in an amalgamated HTML page. The div blocks are siblings. When one page is shown programmatically its siblings are automatically hidden. This allows the application to function quickly since there are no network calls to retrieve content.
All programmatic logic is handled on the browser. The static web server simply delivers HTML, JavaScript, graphic resources, and the manifest file.
User data is saved and restored locally by means of system dialog boxes.
The JavaScript code is separated into two files. The utility.js file contains helper routines. This file can be used without change with other applications. It uses a singleton object so that it can be instantiated multiple times with no overhead. The index.js file contains application logic.
In general, these two files should be concatenated and minified when the application is deployed.
This project can function as a normal web application without tapping into the benefits of an installed PWA. The presence of the manifest.json file, the service-worker.js file, and the call to navigator.serviceWorker.register() function are what make it installable as a PWA.
The manifest.json file and the icon that it references are typically prepared at the beginning of a project and are only infrequently modified after that. On the topic of icons, a good article is Adaptive icon support in PWAs for details about maskable icons with PWAs.
The service-worker.js file is basically boilerplate except for a couple of lines. This file implements the strategy the application will use to fetch resources from the host server, which incidentally can be a static web server. Think of a service worker as a little local web server that your app will contact to retrieve resources. If a resource is available in the local cache, the service worker will deliver that. If a resource is not available, it will contact the host server to get it. In this project, an "offline first" strategy is used. Only after the app is running will it check for updated resources on the server.
The parts of the service-worker.js file that do need to be modified
regularly are the version
and cacheAssets
constants. In this project, the version is simply the UTC timestamp
at the time of deployment. This gets updated with a small script that
sets the value when the resources are synchronized with the host
server. The cache assets are the files that need to be cached to
function offline. This line needs to be updated only when resources
are added or removed from the project, in general not too often.
In a web app like this example it is necessary to generate HTML programmatically. Most apps use some kind of templating library or HTML node generator. This app uses a different technique: certain constructions in the HTML contain the data-template attribute. At program startup, these blocks are deep cloned and saved for later reuse. When these blocks need to be rendered into HTML, a utility function named elementNew() is called that either applies text data to selected nodes in the template, skips certain nodes, or recurses into template sub-blocks. This technique simplifies page generation because the templates themselves are valid HTML and can be checked for semantic and visual correctness before their original text nodes are replaced programmatically.
This page demonstrates various HTML elements and how they are rendered with the classless stylesheet.
A lot of apps use stylesheet classes extensively. This project does
the opposite. It is based on SPCSS that serves to make
the HTML as simple as possible. When the application does need to use
a custom style, try to make use of the HTML's structure in order to
minimize the number of elements that need to assign the class
specifically. For example, rather than apply a class (for example,
class="record"
) to a number of repeating elements, it
might be a lot simpler to instead apply a class (for example,
class="record-container"
to the parent of the repeating
elements. In this example, the style might look like
.record-container > div { ... }
).
Here is a code block with a wide ruler that can be helpful to see how much horizontal and vertical space a certain amount of code consumes. It also demonstrates horizontal scrolling which in most circumstances should be avoided.
1---5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100--105--110--115--120--125--130--135--140--145--150--155--160--165--170--175--180--185--190--195--200--205--210--215--220--225--230--235--240--245--250--255--260--265--270--275--280--285--290--295--300
2
3
4
5
6
7
8
This section demonstrates an image nested within a figure element that includes a caption.
This block demonstrates a simple form. On narrow displays, the email and day of week input fields are shown on separate lines while on wider displays the input fields appear on a single row.
This section shows an example of an HTML table. In general, tables provide a horrible experience on mobile devices unless few narrow columns are used. It is almost always preferable to structure information so that record fields can be displayed in a single column.
Editor | Creator | License | First Release |
---|---|---|---|
GNU Emacs | Richard Stallman | GNU GPLv3+ | 20 Mar 1985 |
Vim | Bram Moolenaar | Vim License | 02 Nov 1991 |
GNU nano | Chris Allegretta | GNU GPLv3 | 18 Nov 1999 |
Notepad++ | Don Ho | GNU GPLv2 | 24 Nov 2003 |
Atom | GitHub | MIT | 26 Feb 2014 |
Visual Studio Code | Microsoft | MIT | 29 Apr 2015 |
This example program is dedicated to Hans Valley, friend and, for too short a time, former colleague. This code may not achieve the appellation of "elegant" that we always strove for, but it does stand on its own without bulky dependencies.
Copyright Maura and Kurt Jung
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.