npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@density/structure

v2.0.1

Published

This set of scripts builds and watches JS projects using popular transpiler and bundler APIs.

Downloads

65

Readme

Dependency Status Package Version License

Structure is a modular build system for frontend projects. It's built to be flexible, transparent, and to supress lock-in to any one technology (we're looking at you, Webpack). There is out of the box support for a number of transpilers (typescript, babel), a number of bundlers (webpack, browserify), and a css post-processor (sass).

Why not use Webpack to do all of this?

  • Flexibility. Configuring Webpack to support a custom stack can be clunky and complex.
  • Transparency. When you buy into the "Webpack way", you end up using tons of plugins that are really opaque. Because you don't really know what transforms your code goes through, it's hard to optimise your bundle easily.
  • Troubleshootability. Due to the above, it's difficult to develop and troubleshoot the development server.

Getting Started

Structure can be installed on its own, or with create-react-app.

create-react-app

For new React applications, structure can be configured as the react-scripts package (does not include a testing framework):

create-react-app --scripts-version @density/structure my-app

NPM

  1. Install structure (npm i -S @density/structure)
  2. Create a structure.js script. Here's an example (more details found in contributing):
// structure.js
const structure = require('@density/structure');

// Start live server
structure.start({

  // Configure modules for assets, styles, transpiler, and bundler
  assets: structure.assets('./src', './build'),
  styles: structure.sass('./src/index.css', './src/**/*.css', './build/app.css'),
  transpiler: structure.typescript('./src/**/*.js', './tmp', { jsx: 2 }),
  bundler: structure.webpack('./tmp/index.js', './build/app.js'),

  // These are defaults but any live-server options can go here
  serverOptions: {
    root: './build',
    file: 'index.html'
  }
});
  1. Run the script to get a live-reloading dev server: node structure.js.

  2. BONUS: add a start script in your package.json file that runs the build script: "start": "node structure.js"

An end to end example:

$ # Set up a tiny project
$ mkdir src/
$ echo "console.log('Hello');" > src/index.js
$ echo "body { color: red; }" > src/index.css
$ cat <<EOF > src/index.html
<html>
 <head>
   <link rel="stylesheet" href="/app.css" />
 </head>
 <body>
   <h1>Hello</h1>
   <script src="/app.js"></script>
 </body>
</html>
EOF
$ # Build the project
$ node structure.js
* Assets ready!
* Styles ready!
* Full transpile done!
* Bundle ready!
* Serving "./build" at http://127.0.0.1:8080

Transpiler/bundler Build System

Structure has scripts to set up and run each step in the build process. Right now it uses the TypeScript compiler API to transpile and watch, and Webpack's API to bundle. The reason for using these specific APIs directly is that we get faster compile times by keeping the compilers in memory. Alternate configurations utilize Babel and Browserify for transpiling and bundling, respectively.

NodeJS Scripts

Subfolders in this project are for purpose-built scripts, like build and start. Let's look at each of those:

build

structure.build is pretty straightforward. It imports the parts used to compile everything and runs a full transpile and bundle with CSS and assets.

This script runs the final ES5 output through UglifyJS by default.

start

structure.start is more complicated. We want incremental or "fast" compilation when we're developing, and a live reload function. The transpiler.transpile() function can be passed a filename to fast-transpile individual files on each save.

With the TypeScript transpiler, each source file is immediately transpiled on every save for a quick refresh, before the full program is typechecked. This is because we're not sure if it is possible to incrementally update the program representation that TypeScript works with internally, and checking the whole program again takes a few extra seconds.

The logic on every TS change is this:

  1. Run the added or updated file through the transpiler right away and write the transpiled output. This uses a persistent reference to a "language service" to process and emit the new file.

  2. Call run or whatever on the bundler instance in memory. This has an entry point main.js and walks the file system to get the rest of the bundle.

  3. In the bundler callback, we can now force the dev server to refresh. The live-server instance is actually monkey-patched at the end of the start script. It has a .change() method and doesn't actually watch files (so we can be sure everything is done before the reload happens).

  4. Finally queue up a "slow" full typecheck + transpile after a one-second delay. This will get us comprehensive error checking in the console, so a few seconds after the browser reloads, any compile-time errors will show up in the console. It makes a brand-new "program" instance every time that processes all files in the project.

The result is we get full typechecking on every change, and fast reload for all valid changes (a very fast reload if sourcemaps are disabled).

Babel & Browserify

Babel and Browserify are not usable out of the box. To enable, add the necessary dependencies to package.json:

  "babel-core": "^6.26.3",
  "babel-preset-es2015": "^6.24.1",
  "babel-preset-react": "^6.24.1",
  "browserify": "^16.2.2",

Internals & Contributing

There's much more detail in CONTRIBUTING.md.