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

@quandis/qbo4.ui.web

v4.0.5

Published

The `qbo4.UI.Web` project contains the web components to add sugar to any UI, including qbo3 and qbo4 UI.

Downloads

1

Readme

Overview

The qbo4.UI.Web project contains the web components to add sugar to any UI, including qbo3 and qbo4 UI.

This replace's the qbo3/Mootools Behaviors concept. Web components are reusable in any modern framework.

Background Reading

Custom Web components

There is a debate about customizing standard html elements. Apple has refused to support customizing existing elements, and Quandis agrees with this approach.

This means that you can do:

<qbo-select></qbo-select>

but you may not do:

<select is="qbo-select"></select>

Components that customize <select> should do this:

@customElement('qbo-select')
export class QboSelect extends QboFetch
{
    ...
    render() {
        ...
        return html`
            <select>
                ${this.options.map(option => html`...`)}
            </select>`;
    }
}

Project Structure

While this project is a Microsoft.NET.Sdk.Web project, it does not include any meaningful server-side code.

Technology Components

| Technology | Config File | Purpose | |-|-|-| |Typescript|tsconfig.json|Type safe version of Javascript. tsc --build is used to compile (transpile) .ts files to .js file.| |Node package manager (npm)|package.json|Javascript equivalent to Nuget package manager.| |Webpack|webpack.config.cjs|Javascript equivalent to MSBuild. Webpack products a single .js and .css file for use by other projects.| |Lit|--|Google's web component library. LitElement is the base class for most qbo4 web components.| |web-test-runner|--|A test runner that runs tests in browser(s)' javascript/DOM engine.|

Folder Structure

|Folder|Purpose| |-|-| |wwwroot|Contains .html pages to enable testing of web components.| |wwwroot/scripts|Contains main.js and main.css files to be linked to by .html pages.| |package|Folder containing the files to be packaged by npm and pushed to an artifact feed. This is specified in package.json| |src|Source .ts files that comprise qbo4.UI.Web's components and libaries.| |tests|Test *.test.ts files for testing components and libraries.|

Typescript (tsconfig.json)

This project includes the Microsoft.Typecript.MSBuild Nuget package, which includes the tsc compiler. When the project is built, MSBuild automatically calls tsc to compile .ts files to .js files.

It is convention to place .ts files in a src folder, and .test.ts files in a tests folder. However, when we publish the package, we want to include only the src files. To address this issue, we have three tsconfig.json files:

  • tsconfig.json: in the root folder
  • src\tsconfig.json: in the src folder, and instructs tsc where to output the files (package folder)
  • tests\tsconfig.json: in the tests folder, and instructs tsc where to output the files (tests (same) folder)

The significant takeaway for our use of tsconfig.json is that we target ESNext for our output, meaning that we produce javascript files that use the latest ECMA standards, including import and export of modules. This means that these libraries will only work with modern browsers, which comprise 94+% of all browsers currently in use. IE is right out.

Node (package.json)

The package.json is used instruct npm how to behave. While it has many options, the most relevent are the defined scripts that allow you to execute node command with a shortcut:

// execute the tests using web-test-runner
npm run test
// package the files for deployment
npm run pack

The following npm commands are not scripts, but you will use frequently:

// install all packages listed in package.json
npm install
// install a package and add it to package.json
npm install <package> --save
// install a package and add it to package.json as a dev dependency
npm install <package> --save-dev
// run any package installed globally
npx <package>

Webpack (webpack.config.cjs)

Typescript projects must be transpiled into javascript, and will leverage modules via import and export. Convention dictates that:

import `lit`;   // This expects lit to be defined in the folder node_modules\lit
import `./qbo`  // This expects qbo to be defined in the current folder

Webpack's job is to look a one (or more) 'entry' javascript files, build a dependency graph of all the imports actually in use, and create a single Javascript file containing all referenced code (a dependency graph). The entry point for qbo modules is qbo.js.

Webpack uses the following configuration files:

  • webpack.config.cjs: common configuration for both development and production, produces output in package\dist
  • webpack.config.dev.cjs: does not minify, does copies package\dist to wwwroot\scripts for testing (merges with webpack.config.cjs)
  • webpack.config.prod.cjs: minifies javascript and css (merges with webpack.config.cjs)

Webpack looks for a webpack.config.js first, but expects the json to be CommonJs, instead of a module as specified in package.json - as needed to tell node our modules use import instead of require. Naming the file with .cjs tells node that file is CommonJS, regardless of what package.json's target says.

The qbo.UI.Web.csproj includes a build target for webpack, so that every time the project is built, new qbo4.js and qbo4.css are created.

<Target Name="NpmRunPack" AfterTargets="Build">
	<Exec Command="npm run packprod" />
</Target>

paired with the pack script defined in pacakge.json:

{ ...
  "scripts": {
    "packprod": "webpack --config webpack.prod.cjs --no-color"
  },
  ...
}

HTML Coding Guidelines

When creating web pages, features should be implemented with:

  • HTML, first, if possible,
  • CSS, second, if possible,
  • Javascript, otherwise

Web Components

When designing reusable browser-based components, web components should be used. Web components use Javascript, HTML and CSS to define new tags ~~or extend existing tags~~ , and scope all functionality to a shadow DOM. This allows a given component to use javascript without worrying that it will interfere with other components.

The goal of creating web components is to strive to ensure QBO components can be mixed into a variety of frameworks, including Angular and React.

In most cases, Quandis recommends use of Google's Lit library to speed the development of pure web components.

A sampling custom components includes:

|Component|Purpose| |-|-| |qbo-fetch|Acts as a base class for elements that need to do API calls (via Javascript's fetch statement).| |qbo-select|Renders a <select> element with options from the results of an API call.| |qbo-popup|Renders a popup, with content optionally coming from an API call (via qbo-fetch).| |qbo-logging|Provides UI around handling errors.|

Form validation

HTML5 supports extensive form validation; use it! Examples:

<input name="zipcode" type="text" pattern="\d{5}(-\d{4})?"/>
<input name="creditcard" type="text" pattern="[0-9]{13,16}"/>

Typescrpit / Javascript Coding Guidelines

  • Use the MDN Style Guide (which Microsoft also uses)
  • Use const and let instead of var
  • Use camelcase for variables and function names
const myLongVariableName = "foo";
  • Use template literals for code readability
const firstName = "Bob";
const lastName = "Jones";
const result = `Hello ${firstName}, ${lastName}`;
  • Omit the protocol from links to other sites, if possible, to support http and https
<style src="//maps.googleapis.com/maps/api/js"/>

Namespacing

Use modules via the export and import features to build javascript libraries. Related classes and functions should be imported as a module. For example, qbo4-related modules:

  • src
    • qbo.ts
    • qbo-fetch.ts
    • qbo-json.ts
    • qbo-select.ts

where qbo.js aggregates related classes an functions:

export * from './qbo-fetch.js'
export * from './qbo-json.js'
export * from './qbo-select.js'

and the website's root includes a qbo4.js created by webpack:

import * as qbo4 from './qbo4.js';

To use qbo4 from a browser debugger window:

const qbo = await import('/scirpts/qbo4.js'); 
// now you can access qbo.* functions

Error handling in the browser

  • Assume our code will fail
  • Log errors to the server
  • Our code, not the browser, should handle errors
  • Identify errors that might occur (arguments, network)
  • throw at a low level, catch at a high level
  • Distinguish between fatal and non-fatal
  • Global debug mode: help the developer figure out the problem

Credit Nicholas Zakas

Comments

Quandis shall follow the TSDoc to work with Visual Studio Intellisense.

/* @description These are sample comments
 * @param foo {string} Foo is used to ...
 * @param bar {array} Each item in bar is used to ...
 * @returns {object} An object representing ...
*/
qbo4.someMethod = function (foo, bar) {...}

Third Party Libraries

  • Use native Javascript methods ahead of third party library methods
    • e.g. document.getElementById(id) is preferrable to jQuery's $('#id')[0].
    • e.g. {array}.forEach(...) is preferable to Mootool's {array}.each(...)

|Library|qbo3|qbo4|Notes| |-|-|-|-| |Mootools|yes|no|Deprecated; not under development.| |jQuery|yes|yes|For sugar not supported by the DOM. Use noconflict; $ shall be used for Mootools in qbo3.| |Google Visualizations|yes|yes|For charting.| |Bootstrap|yes|yes|For styling and layout.| |Dropzone|yes|yes|For file upload controls.| |Modernizr|yes|yes|For older browsers (consumer-facing sites).|

Feature adoption

|Feature|qbo3|qbo4|Notes| |-|-|-|-| |Promises|yes|yes|| |async/await|yes|yes||

Use new features only if available to 90% or more of global users.

References

Typescript in a Microsoft Stack

A basic Typescript project (.esproj file) looks something like this:

<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/0.5.74-alpha">
  <PropertyGroup>
    <!-- Command to run on project build -->
    <BuildCommand>npm run build</BuildCommand>
    <!-- Command to run on project clean -->
    <CleanCommand>npm run clean</CleanCommand>
  </PropertyGroup>
  <ItemGroup>
    <Folder Include="build\" />
  </ItemGroup>
</Project>

The following files are automatically added:

|File|Description| |-|-| |tsconfig.json|Typescript configuration file that provides tsc (a node package that is the Typescript compiler) with it's build options.| |package.json|Node.js configuration file that provides npm.exe (the Node Package Manager) with the Node packages to include.| |nuget.config|Sources to use for Nuget packages.|

Building

  • When a developer select Project > Build, the BuildCommand is executed, which in turn runs npm run build.
  • npm looks for a build script defined in package.json, which is defined in by the scrips entry in package.json:
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc --build",
    "clean": "tsc --build --clean"
},
  • tsc is the Typescript compiler, which is installed as a Node package.

By default, calling tsc --build will find any .ts files, and compile them to .js and .js.map files.

The .js.map file is a mapping between the generated/transpiled/minified JavaScript file and one or more original source files. The main purpose of Sourcemaps is to aid debugging. If there is an error in the generated code file, the map can tell you the original source file location. That's it.

This all happens in the root of the project.

Quandis Customizations

/src and /build folders

A common convention is to store .ts files in a /src folder, and the generated .js files in a /build folder. This is enabled by modifying the tsconfig.json file:

{
    "compilerOptions": {
        "experimentalDecorators": true, // for Lit compatibility
	    "outDir": "./js",
	    ...
    },
    "include": [ "src/**/*", "tests/**/*" ]
}

Testing

Lit recommends using @web-test-runner for testing Lit-based web components. The web-test-runner tests javascript against actual browser javascript engines, rather than Node.js. This is important because Node.js does not support the DOM, and Lit is a DOM-based library. The @web/test-runner-playwright enables testing against Chrome, Safari and Edge.

To install web-test-runner:

npm install --save-dev @web/test-runner
npm install --save-dev @web/test-runner-playwright

To run tests, packages.json includes:

{
    ...
    "scripts": {
        "test": "web-test-runner \"js/tests/**/*.test.js\" --node-resolve",
        "test:watch": "web-test-runner \"js/tests/**/*.test.js\" --node-resolve --watch",
        "test:all": "web-test-runner \"js/tests/**/*.test.js\" --node-resolve --playwright --browsers chromium firefox webkit --static-logging",
    },
    ...
}

Publish Node Packages to Azure Devops

By default, npm will publish to the npmjs.com registry. To publish to a private Azure Devops feed, you will create 2 .npmrc files:

  • c:\users\your.username\.npmrc: this will contain authentication info
  • {project folder}\.npmrc: this will contain just the feed URL

The private npmrc file will look something like this:

qbo4:registry=https://pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/ 
always-auth=true
; begin auth token
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/:username=quandis
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/:_password={your Devops PAT, base64 encoded}
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/:email=npm requires email to be set but doesn't use the value
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/:username=quandis
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/:_password={your Devops PAT, base64 encoded}
//pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/:email=npm requires email to be set but doesn't use the value
; end auth token

Yor PAT is an Azure Devops Personal Access Token, which you have configured for Visual Studio to pull Quandis Nuget packages You can use Fiddler's TextWizard to base64 encode your PAT.

The project .npmrc file will look something like this:

registry=https://pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/ 

Some useful npm commands:

// list all npm config settings, including registries defined in various .npmrc files
npm config list

// publish to a specific registry
npm publish --registry=https://pkgs.dev.azure.com/quandis/_packaging/qbo4-Build/npm/registry/

// publish to whatever registry is defined in the local .npmrc file
npm publish

// increment the version number in package.json
npm version patch

Notes