• Stars
    star
    3,123
  • Rank 13,776 (Top 0.3 %)
  • Language
    JavaScript
  • Created almost 6 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

(WIP) Universal PWA Builder
PWA

WORK IN PROGRESS


Features

  • Framework Agnostic
    Build with your preferred framework or with none at all!
    Official presets for Preact, React, Vue, and Svelte.

  • Plug 'n Play
    Don't worry about configuration, unless you want to.
    Presets and plugins are automatically applied. Just install and go!

  • Fully Extensible
    Includes a plugin system that allows for easy, fine-grain control of your configuration... when needed.

  • Feature Rich
    Supports Babel, Bublรฉ, Browserslist, TypeScript, PostCSS, ESLint, Prettier, and Service Workers out of the box!

  • Instant Prototyping
    Quickly scaffold new projects with your preferred view library and toolkit.
    Kick it off with a perfect Lighthouse score!

  • Static Site Generator
    Export your routes as "pre-rendered" HTML.
    Great for SEO and works on any static hosting service.

Installation

PWA is split up into two main components (core and cli) in addition to its list of presets and plugins.

While most will opt for the CLI, the core module handles all configuration and can be used as a standalone module.

Please refer to each package for installation, API, and Usage information.

Quick Start

# Install globally
$ npm install --global @pwa/cli
# OR
$ yarn global add @pwa/cli

# Display CLI's help text
$ pwa --help

# Generate new project
$ pwa init

Note: The global modifiers are only required for global command-line usage!
Local devDependency installation will also work, but then pwa usage is limited to the project.

Concepts

Please read about Progressive Web Apps if the term is unfamiliar to you.

Presets

Presets are collections of plugins that are tailored for a particular framework.

While there may be "official" presets, this does not mean that PWA can only support these candidates! The current options are:

These packages are auto-loaded during PWA's initialization and are applied first, before any Plugins or custom configuration. This means that you always have the option to override a value or setting shipped within the Preset.

Plugins

Plugins are (typically) individual features or chunks of configuration that are encapsulated for easy/automatic application within your build process.

While there may be "official" plugins, this does not mean that PWA can only support these functionalities! The current plugins include:

These packages are auto-loaded during PWA's initialization and are applied second, after any Presets and before custom configuration. This allows Plugins to override settings from Presets.

Plugins may (sometimes) expose a new key on the config tree and then reference this value later in composition. This allows the end-user to change the Plugin's settings before running the build.

Please see @pwa/plugin-critters for an example of this practice.

Commands

This section applies to @pwa/cli specifically.

Build

Build your application for production

$ pwa build --help

  Description
    Build production assets

  Usage
    $ pwa build [src] [options]

  Options
    --analyze     Launch interactive Analyzer to inspect production bundle(s)
    -o, --dest    Path to output directory  (default build)
    -h, --help    Displays this message

Export

Export routes' HTML for static hosting

Instead of --routes, you may define a routes array within pwa.config.js config file.

If no routes are defined in either location, PWA will traverse your "@pages"-aliased directory (default: src/pages/**) and attempt to infer URL patterns from the file structure.

In the event that no files exist within that directory, PWA will show a warning but still scrape the index ("/") route.

$ pwa export --help

  Description
    Export pre-rendered pages

  Usage
    $ pwa export [src] [options]

  Options
    -o, --dest        Path to output directory  (default build)
    -w, --wait        Time (ms) to wait before scraping each route  (default 0)
    -r, --routes      Comma-delimited list of routes to export
    -i, --insecure    Launch Chrome Headless without sandbox
    -h, --help        Displays this message

Important: Using export requires a local version of Chrome installed! See chrome-launcher.
Additionally, the --insecure flag launches Chrome without sandboxing. See here and here for help.

Watch

Develop within a live-reload server

Within your pwa.config.js's webpack config, any/all devServer options are passed to Webpack Dev Server.

$ pwa watch --help

  Description
    Start development server

  Usage
    $ pwa watch [src] [options]

  Options
    -H, --host     A hostname on which to start the application  (default localhost)
    -p, --port     A port number on which to start the application  (default 8080)
    -q, --quiet    Disable logging to terminal, including errors and warnings
    --https        Run the application over HTTP/2 with HTTPS
    --key          Path to custom SSL certificate key
    --cert         Path to custom SSL certificate
    --cacert       Path to custom CA certificate override
    -h, --help     Displays this message

Build vs Export

Export can be thought of as "Build 2.0" โ€” it spins up a Headless Chrome browser and programmatically scrapes your routes.

This is ideal for SEO, PWA behavior, and all-around performance purposes, as your content will exist on the page before the JavaScript application is downloaded, parsed, boots, and (finally) renders the content.

The generated HTML pages will be placed in your build directory. A /login route will be exported as build/login/index.html โ€” this makes it compatible with even the "dumbest" of static hosting services!

Note: Running export will automatically run build before scraping.

Configuration

Overview

All configuration within the PWA tree is mutable! Presets, Plugins, and your custom config file write into the same object(s). This is great for composability and extensibility, but be warned that your custom config may break the build if you're not careful.

๐Ÿ’ก Official presets & plugins are controlled releases and are ensured to play nicely with one another.

The config object(s) for your project are assembled in this sequence:

  1. Presets: All non-webpack config keys
  2. Plugins: All non-webpack config keys
  3. Custom: All non-webpack config keys
  4. Presets: The webpack config key, if any
  5. Plugins: The webpack config key, if any
  6. Custom: The webpack config key, if any

Because the final config object is passed to Webpack, internally, the webpack key always runs last as it composes & moves everything into its relevant loaders, plugins, etc.

Important: When defining a custom webpack key it must always be a function!

Mutations

Every config key can be defined or mutated in the same way!

Any non-Function key will overwrite the existing value. This allows strong opinions and/or allows a Plugin to define a new config key and reference it later on.

Any Function key will receive the existing, matching config-value for direct mutation. This is for fine-grain control over the existing config.

// defaults:
exports.hello = { foo:1, bar:2 };
exports.world = ['How', 'are', 'you?'];

// preset/plugin/custom:
exports.hello = function (config) {
  config.bar = 42;
  config.baz = [7, 8, 9];
}
exports.world = ['I', 'am', 'fine'];
exports.HOWDY = 'PARTNER!';

// result:
exports.hello = {
  foo: 1,
  bar: 42,
  baz: [7, 8, 9]
}
exports.world = ['I', 'am', 'fine'];
exports.HOWDY = 'PARTNER!';

Functions

Any config key that is a function will have the signature of (config, env, opts).

config

Type: Mixed

This will be the existing value for the current key. It will typically be an Object, but not always.

It will also be undefined if/when defining a new config key โ€” if you know that to be the case, you shouldn't be using a Function~!

env

Type: Object

Will be the environmental values for this command.
This is passed from @pwa/core's options.

The env.cwd, env.src, env.dest, env.log, env.production and env.webpack keys are always defined.
Anything else is contextual information for the current command being run.

opts

Type: Object

Direct access to configuraton keys, except webpack.

As an example, this can be used within a Plugin for gaining insight or gaining access to other packages' settings.

The default config keys (except webpack) will always be present here.

Config Keys

The following keys are defined by default within every PWA instance. You may mutate or compose with them accordingly.

babel

Type: Object
Default: Link

Your Babel config object.

css

Type: Object
Default: Link

Core CSS behavior โ€”ย see css-loader for options.

html

Type: Object
Default: Link

Your HTML plugin configuration โ€”ย see html-webpack-plugin for options.

less

Type: Object
Default: Link

Any less-loader options โ€”ย see less-loader for documentation.

Note: This is the entire loader config; you may need to include the lessOptions nested object.

postcss

Type: Object
Default: Link

Your PostCSS config โ€” you may also use any config file/method that postcss-loader accepts.

Important: The postcss.plugins key cannot be a function!

sass

Type: Object
Default: Link

Any sass-loader options โ€”ย see sass-loader for documentation.

This object will be used for both .scss and .sass file extensions.
The .sass extension will automatically enforce the indentedSyntax option.

Note: This is the entire loader config; you may need to include the sassOptions nested object.

stylus

Type: Object
Default: Link

Any stylus-loader options โ€”ย see stylus-loader for documentation.

terser

Type: Object
Default: Link

The options for Terser Plugin.

Note: Expecting UglifyJS? It's no longer maintained!
The Terser configuration is nearly identical โ€“ simply rename uglifyOptions to terserOptions ๐Ÿ‘

webpack

Type: Function

The main handler for all of PWA!
When you define a custom webpack, you are not overriding this function. Instead, you are manipulating Webpack's config immediately before PWA executes the build.

Browserslist

The preferred method for customizing your browser targets is thru the browserslist key within your package.json file.

Note: When creating a new project with pwa init, our recommended config is automatically added for you!

You may choose to change the default values, or use any configuration method that Browserslist accepts.

The resulting array of browser targets will be automatically applied to Autoprefixer, Babel, Bublรฉ, PostCSS, Stylelint, ...etc.

Customizing

Presets and Plugins are just encapsulated config mutations โ€” that's it!

Now, if you want to further customize your PWA build, beyond what your installed Presets & Plugins are giving you, then you can create a pwa.config.js in your project's root directory.

Note: Your new pwa.config.js file should sit alongside your package.json ๐Ÿ‘

With this file, you may mutate or compose any of the config keys that either PWA or its Plugins exposes to you.

Here is an example custom config file:

// pwa.config.js
const OfflinePlugin = require('offline-plugin');

// Mutate "@pwa/plugin-eslint" config
exports.eslint = function (config) {
  config.formatter = require('eslint-friendly-formatter');
};

// Add new PostCSS Plugin
exports.postcss = function (config) {
  config.plugins.push(
    require('postcss-flexbugs-fixes')
  );
};

// Export these pages during "pwa export" command
exports.routes = ['/login', '/register', '/articles/hello-world'];

// Update Webpack config; ENV-dependent
exports.webpack = function (config, env) {
  let { production, webpack } = env;

  if (production) {
    config.plugins.push(
      new OfflinePlugin(),
      new webpack.DefinePlugin({
        MY_API: JSON.stringify('https://api.example.com')
      })
    );
  } else {
    config.devServer.https = true;
    config.plugins.push(
      new webpack.DefinePlugin({
        MY_API: JSON.stringify('http://staging.example.com')
      })
    );
  }
};

Credits

A huge thank-you to Jimmy Moon for donating the @pwa organization on npm! ๐Ÿ™Œ Aside from being the perfect name, we wouldn't be able to have automatic preset/plugin resolution without a namespace!

Incredible thanks to the giants whose shoulders this project stands on~! โค๏ธ

PWA was originally conceived in 2016 but at that time, it wasn't yet possible to build it with the feature set I had in mind. Since then, an amazing amount of work has been done on Webpack and its ecosystem, which now makes the project goals feasible.

There's no question that PWA takes inspiration from popular CLI applications, like Preact CLI, Vue CLI, and Create React App. They most definitely paved the way. I've used, learned from, and refined my wishlist over years while using these tools. Despite their greatness, I still found a need for a universal, framework-agnostic PWA builder that could unify all these great libraries.

License

MIT ยฉ Luke Edwards

More Repositories

1

clsx

A tiny (239B) utility for constructing `className` strings conditionally.
JavaScript
7,354
star
2

polka

A micro web server so fast, it'll make you dance! ๐Ÿ‘ฏ
JavaScript
5,266
star
3

uvu

uvu is an extremely fast and lightweight test runner for Node.js and the browser
JavaScript
2,938
star
4

taskr

A fast, concurrency-focused task automation tool.
JavaScript
2,528
star
5

sockette

The cutest little WebSocket wrapper! ๐Ÿงฆ
JavaScript
2,398
star
6

worktop

The next generation web framework for Cloudflare Workers
TypeScript
1,635
star
7

kleur

The fastest Node.js library for formatting terminal text with ANSI colors~!
JavaScript
1,593
star
8

klona

A tiny (240B to 501B) and fast utility to "deep clone" Objects, Arrays, Dates, RegExps, and more!
JavaScript
1,537
star
9

dequal

A tiny (304B to 489B) utility to check for deep equality
JavaScript
1,271
star
10

tsm

TypeScript Module Loader
TypeScript
1,164
star
11

tinydate

A tiny (349B) reusable date formatter. Extremely fast!
JavaScript
1,060
star
12

sirv

An optimized middleware & CLI application for serving static files~!
JavaScript
1,023
star
13

sade

Smooth (CLI) Operator ๐ŸŽถ
JavaScript
1,009
star
14

rosetta

A general purpose internationalization library in 292 bytes
JavaScript
766
star
15

navaid

A navigation aid (aka, router) for the browser in 850 bytes~!
JavaScript
755
star
16

dset

A tiny (194B) utility for safely writing deep Object values~!
JavaScript
739
star
17

uid

A tiny (130B to 205B) and fast utility to generate random IDs of fixed length
JavaScript
634
star
18

httpie

A Node.js HTTP client as easy as pie! ๐Ÿฅง
JavaScript
575
star
19

ganalytics

A tiny (312B) client-side module for tracking with Google Analytics
JavaScript
575
star
20

trouter

๐ŸŸ A fast, small-but-mighty, familiar fish...errr, router*
JavaScript
563
star
21

regexparam

A tiny (394B) utility that converts route patterns into RegExp. Limited alternative to `path-to-regexp` ๐Ÿ™‡โ€โ™‚๏ธ
JavaScript
555
star
22

dimport

Run ES Module syntax (`import`, `import()`, and `export`) in any browser โ€“ even IE!
JavaScript
547
star
23

mri

Quickly scan for CLI flags and arguments
JavaScript
533
star
24

tempura

A light, crispy, and delicious template engine ๐Ÿค
JavaScript
514
star
25

calendarize

A tiny (202B) utility to generate calendar views.
JavaScript
471
star
26

formee

A tiny (532B) library for handling <form> elements.
JavaScript
443
star
27

qss

A tiny (294b) browser utility for encoding & decoding a querystring.
JavaScript
408
star
28

preact-starter

Webpack3 boilerplate for building SPA / PWA / offline front-end apps with Preact
JavaScript
387
star
29

uuid

A tiny (~230B)and fast UUID (V4) generator for Node and the browser
JavaScript
386
star
30

vegemite

A Pub/Sub state manager you'll love... or hate
JavaScript
373
star
31

resolve.exports

A tiny (952b), correct, general-purpose, and configurable `"exports"` and `"imports"` resolver without file-system reliance
TypeScript
351
star
32

polkadot

The tiny HTTP server that gets out of your way! ใƒป
JavaScript
322
star
33

matchit

Quickly parse & match URLs
JavaScript
321
star
34

fetch-event-stream

A tiny (736b) utility for Server Sent Event (SSE) streaming via `fetch` and Web Streams API
TypeScript
321
star
35

flru

A tiny (215B) and fast Least Recently Used (LRU) cache
JavaScript
310
star
36

mrmime

A tiny (2.8kB) and fast utility for getting a MIME type from an extension or filename
TypeScript
300
star
37

watchlist

Recursively watch a list of directories & run a command on any file system changes
JavaScript
261
star
38

arr

A collection of tiny, highly performant Array.prototype alternatives
JavaScript
255
star
39

ley

(WIP) Driver-agnostic database migrations
JavaScript
254
star
40

flattie

A tiny (203B) and fast utility to flatten an object with customizable glue
JavaScript
254
star
41

webpack-messages

Beautifully format Webpack messages throughout your bundle lifecycle(s)!
JavaScript
246
star
42

obj-str

A tiny (96B) library for serializing Object values to Strings.
JavaScript
225
star
43

templite

Lightweight templating in 150 bytes
JavaScript
221
star
44

ms

A tiny (414B) and fast utility to convert milliseconds to and from strings.
JavaScript
200
star
45

nestie

A tiny (215B) and fast utility to expand a flattened object
JavaScript
199
star
46

throttles

A tiny (139B to 204B) utility to regulate the execution rate of your functions
JavaScript
195
star
47

hexoid

A tiny (190B) and extremely fast utility to generate random IDs of fixed length
JavaScript
185
star
48

fromnow

A tiny (339B) utility for human-readable time differences between now and past or future dates.
JavaScript
178
star
49

astray

Walk an AST without being led astray
JavaScript
177
star
50

tmp-cache

A least-recently-used cache in 35 lines of code~!
JavaScript
174
star
51

bundt

A simple bundler for your delicious modules
JavaScript
167
star
52

wrr

A tiny (148B) weighted round robin utility
JavaScript
164
star
53

freshie

(WIP) A fresh take on building universal applications with support for pluggable frontends and backends.
TypeScript
153
star
54

svelte-ssr-worker

A quick demo for rendering Svelte server-side (SSR), but within a Cloudflare Worker!
JavaScript
152
star
55

totalist

A tiny (195B to 224B) utility to recursively list all (total) files in a directory
JavaScript
148
star
56

typescript-module

Template repository for authoring npm modules via TypeScript
TypeScript
141
star
57

sublet

Reactive leases for data subscriptions
JavaScript
139
star
58

escalade

A tiny (183B to 210B) and fast utility to ascend parent directories
JavaScript
138
star
59

webpack-route-manifest

Generate an asset manifest file, keyed by route patterns!
JavaScript
127
star
60

url-shim

A 1.5kB browser polyfill for the Node.js `URL` and `URLSearchParams` classes.
JavaScript
123
star
61

semiver

A tiny (153B) utility to compare semver strings.
JavaScript
119
star
62

cfw

(WIP) A build and deploy utility for Cloudflare Workers.
TypeScript
113
star
63

svelte-demo

Multi-page demo built Svelte 3.x and Rollup with code-splitting
Svelte
113
star
64

webpack-format-messages

Beautiful formatting for Webpack messages; ported from Create React App!
JavaScript
111
star
65

gittar

๐ŸŽธ Download and/or Extract git repositories (GitHub, GitLab, BitBucket). Cross-platform and Offline-first!
JavaScript
111
star
66

saturated

A tiny (203B) utility to enqueue items for batch processing and/or satisfying rate limits.
JavaScript
110
star
67

webpack-critical

Extracts & inlines Critical CSS with Wepack
JavaScript
109
star
68

pages-fullstack

Demo SvelteKit application running on Cloudflare Pages
Svelte
102
star
69

sort-isostring

A tiny (110B) and fast utility to sort ISO 8601 Date strings
JavaScript
98
star
70

colors-app

๐ŸŽจ A PWA for copying values from popular color palettes. Supports HEX, RGB, and HSL formats.
JavaScript
95
star
71

salteen

A snappy and lightweight (259B) utility to encrypt and decrypt values with salt.
JavaScript
95
star
72

is-offline

A tiny (174B) library to detect `offline` status & respond to changes in the browser.
JavaScript
91
star
73

seolint

(WIP) A robust and configurable SEO linter
TypeScript
86
star
74

rafps

A tiny (178B) helper for playing, pausing, and setting `requestAnimationFrame` frame rates
JavaScript
82
star
75

preact-cli-ssr

A quick demo for adding SSR to a Preact CLI app
JavaScript
79
star
76

webpack-modules

Handle `.mjs` files correctly within webpack
JavaScript
71
star
77

csprng

A tiny (~90B) isomorphic wrapper for `crypto.randomBytes` in Node.js and browsers.
JavaScript
66
star
78

classico

A tiny (255B) shim when Element.classList cannot be used~!
JavaScript
62
star
79

premove

A tiny (201B to 247B) utility to remove items recursively
JavaScript
62
star
80

mk-dirs

A tiny (381B to 419B) utility to make a directory and its parents, recursively
JavaScript
54
star
81

primeval

A tiny (128B) utility to check if a value is a prime number
JavaScript
51
star
82

loadr

Quickly attach multiple ESM Loaders and/or Require Hooks together but without the repetitive `--experimental-loader` and/or `--require` Node flags
JavaScript
49
star
83

preact-progress

Simple and lightweight (~590 bytes gzip) progress bar component for Preact
JavaScript
49
star
84

route-manifest

A tiny (412B) runtime to retrieve the correct entry from a Route Manifest file.
JavaScript
46
star
85

svelte-preprocess-esbuild

A Svelte Preprocessor to compile TypeScript via esbuild!
TypeScript
44
star
86

preact-scroll-header

A (800b gzip) header that will show/hide while scrolling for Preact
JavaScript
41
star
87

inferno-starter

Webpack2 boilerplate for building SPA / PWA / offline front-end apps with Inferno.js
JavaScript
41
star
88

rollup-route-manifest

A Rollup plugin to generate an asset manifest, keyed by route patterns ("route manifest")
JavaScript
40
star
89

onloaded

A tiny (350B) library to detect when images have loaded.
JavaScript
38
star
90

webpack-plugin-replace

Replace content while bundling.
JavaScript
36
star
91

route-sort

A tiny (200B) utility to sort route patterns by specificity
JavaScript
35
star
92

scorta

A tiny (330B to 357B) and fast utility to find a package's hidden supply / cache directory.
JavaScript
33
star
93

local-hostname

A tiny (171B) utility to check if a hostname is local
JavaScript
32
star
94

taskr-outdated

A generator & coroutine-based task runner. Fasten your seatbelt. ๐Ÿš€
JavaScript
32
star
95

rewrite-imports

Rewrite `import` statements as `require()`s; via RegExp
JavaScript
31
star
96

preact-offline

A (300b gzip) component to render alerts/messages when offline.
JavaScript
29
star
97

fly-kit-preact

A starter kit for building offline / SPA / PWA apps with Preact
JavaScript
28
star
98

fannypack

The tool belt for front-end developers
JavaScript
28
star
99

is-ready

A tiny (309B) library to detect when `window` globals are defined and ready to use~!
JavaScript
28
star
100

ava-http

Async HTTP request wrapper ๐Ÿš€
JavaScript
25
star