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

requirejs-esm-preprocessor

v2.0.0

Published

Preprocessor of JavaScript modules in RequireJS projects converting ESM to AMD.

Downloads

36

Readme

ESM to AMD Preprocessor for RequireJS

Latest version Dependency status

A preprocessor of JavaScript modules in RequireJS projects converting ESM to AMD. It takes care only of the module format; it does not transpile the language and that is why it is a lot faster than plugins using Babel. If you need to transpile the code to an earlier ECMAScript version, have a look at requirejs-babel7.

A file preprocessor is a lot less intrusive than a RequireJS plugin. However, it requires a pluggable development web server, so that a plugin (compatible with connect middleware) can be registered in it. The production web server has not limitations, because the bundled output of RequireJS optimizer contains AMD modules. (Preprocessing takes place in the onBuildRead callback.) Have look at requirejs-esm if you are looking for a RequireJS plugin withtou these limitations.

The official RequireJS optimizer (r.js) does not wire up source maps from the original (not transpiled) sources to the source map of the output bundle. It makes this or similar preprocessors unfeasible for serious work. If you want the proper support for source maps, replace the official optimizer package (requirejs) with the forked @prantlf/requirejs, which is fixed.

Installation

This module can be installed in your project using NPM, PNPM or Yarn. Make sure, that you use Node.js version 14 or newer.

npm i -D requirejs-esm-preprocessor
pnpm i -D requirejs-esm-preprocessor
yarn add requirejs-esm-preprocessor

Usage

Add the following property to the build configuration file for the RequireJS optimizer:

{
  onBuildRead: (moduleName, path, contents) => {
    const { preprocess } = nodeRequire('requirejs-esm-preprocessor')
    return preprocess({ path: moduleName, contents })
  }
}

Create a file server.js to be used as the development web server:

const { serve } = require('requirejs-esm-preprocessor')
serve({
  // Transform local sources; not require.js loaded on the page from node_modules
  isScript: path => path.endsWith('.js') && path.startsWith('/src/')
})

If your project contains source scripts ending with .js, which should be transpiled, and all other scripts loaded on pages by script elements end with .min.js, you can use the ready-to-use command line server:

requirejs-esm-serve

You can use the ESM module format in modules loaded as dependencies by RequireJS. The main application script cannot be an ESM module, because it would be wrapped in a define statement. The main application script i ssupposed to include a require statement to perform the application initialisation.

This plugin transpiles only ESM source files. If it detects a statement calling functions define, require or require.config on the root level of the source file, it will return the text of the source file as-is.

See also a demo-local project, which includes sources only from the local src directory:

npm run start:local
open http://localhost:8967/demo-local/normal.html
open http://localhost:8967/demo-local/optimized.html

Advanced

You can bundle ESM modules from outside of your source root too. For example:

import { html, render } from 'lit-html/lit-html'
render(html`<p>Hello, world!<p>`, document.body)

Let lit-html be a path alias in the RequireJS configuration pointing to a directory among NPM dependencies outside the source root:

paths: {
  'lit-html': '../node_modules/lit-html'
},

However, the relative paths of model dependencies outside the source root will be based on the source root, instead on the module path outside of the source root. One way how to deal with this problem is resolving the relative module paths manually by trimming the directories from absolute module paths:

{
  onBuildRead: (moduleName, path, contents) => {
    const { preprocess } = nodeRequire('requirejs-esm-preprocessor')
    const cwd = process.cwd()
    // Base all modules from local sources on the source root
    const appDir = `${cwd}/src`
    // Remove the root of external modules; expect the external
    // module directories in the RequireJS `paths` configuration
    const dirMap = { [`${cwd}/node_modules/`]: '' }
    return preprocess({ path, contents, appDir, dirMap })
  }
}

If you want to merge the NPM dependencies bundled in your project with the other outside of your project, you can rebase their root, so that they would appear next to with other external static assets in the browser debugger:

{
  onModuleBundleComplete: ({ path }) => {
    const { rebaseMapFile } = nodeRequire('requirejs-esm-preprocessor')
    rebaseMapFile(`${path}.map`, { [`${process.cwd()}/node_modules/`]: '../node_modules/' });
  }
}

The development web server must not transform static assets that are not meant to be bundled in the optimised output:

const { serve } = require('requirejs-esm-preprocessor')
serve({
  isScript: path => path.endsWith('.js') &&
    !path => path.endsWith('.min.js') &&
    !path.endsWith('/require.js'),
  dirMap: { '/node_modules/': '' }
})

See also a demo-extern project, which includes sources from the local src directory and from node_modules outside of it:

npm run start:extern
open http://localhost:8967/demo-extern/normal.html
open http://localhost:8967/demo-extern/optimized.html

API

interface DirMap {
  [ key: string ]: string
}

type NeedsResolve = (sourcePath: string, currentFile: string) => boolean

interface ResolveOptions {
  dirMap?: DirMap
  needsResolve?: NeedsResolve
}

resolvePath(sourcePath: string, currentFile: string, options?: ResolveOptions): string

rebasePath(path: string, dirMap?: DirMap): string
rebaseMap(map: object, dirMap?: DirMap): void
rebaseMapFile(file: string, dirMap?: DirMap): void

type ResolvePath = ((sourcePath: string, currentFile: string, options?: ResolveOptions) => string) | false
type IsScript = (path: string) => boolean

preprocess(options?: {
  path: string, contents: string, dirMap?: DirMap, appDir?: string,
  needsResolve?: NeedsResolve, resolvePath?: ResolvePath = false,
  sourceMap?: boolean = true, verbose?: boolean, silent?: boolean }): string

type Handler = (req: http.OutgoingMessage, res: http.IncomingMessage, next: () => void) => void

serveFile(req: http.OutgoingMessage, res: http.IncomingMessage, path: string) :void
serveScript(req: http.OutgoingMessage, res: http.IncomingMessage, options?: {
  path: string, fullPath: string, dirMap?: DirMap, appDir?: string,
  needsResolve?: NeedsResolve, resolvePath?: ResolvePath = false,
  sourceMap?: boolean = true, verbose?: boolean, silent?: boolean }): void
preprocessor(options?: {
  root?: string = '.', scriptsOnly?: boolean, fallthrough?: boolean,
  setHeaders?: (res: http.Response, path: string, stat: fs.Stat) => void,
  cache?: boolean, isScript?: IsScript, dirMap?: DirMap, appDir?: string,
  needsResolve?: NeedsResolve, resolvePath?: ResolvePath = false,
  sourceMap?: boolean = true, verbose?: boolean, silent?: boolean }): Handler

interface ServerOptions {
  root?: string = '.', isScript?: IsScript, scriptsOnly?: boolean
  host: string = process.env.HOST || '0.0.0.0'
  port: number = process.env.PORT || 8967
  dirMap?: DirMap, appDir?: string, sourceMap?: boolean = true
  needsResolve?: NeedsResolve, resolvePath?: ResolvePath = false
  secureOptions?: {
    port: number = process.env.SECURE_PORT || 9876
    key?: string | Blob | Buffer = 'dist/certificates/localhost.key'
    cert?: string | Blob | Buffer = 'dist/certificates/localhost.crt'
    allowHTTP1?: boolean = true
  }
  logOptions?: {
    format?: string = 'dev', errorsOnly?: boolean = true
    servedOnly?: boolean = true, transforms?: boolean, silent?: boolean
  }
  leadingHandlers?: Handler[]
  middleHandlers?: Handler[]
  trailingHandlers?: Handler[]
  favicon?: boolean
  server?: http.Server | false
  secureServer?: http.Server | false
  handler?: Handler
}

defaultUsage(): void
defaultUnknownArg(arg: string): boolean
configure(options: {
  args: string[], version: string,
  usage?: () => void, unknownArg?: (arg: string) => boolean
}): {
  server?: boolean, secureServer?: boolean, root?: string,
  host?: string, port?: number, secureOptions?: { port: number },
  errorsOnly: boolean, servedOnly: boolean,
  transforms?: boolean, silent?: boolean
}

createHandler(options?: ServerOptions): Handler
createServer(options?: ServerOptions, handler?: Handler): http.Server
createSecureServer(options?: ServerOptions, handler?: Handler): Promise<http.Server>
startServer(options?: ServerOptions,
  server?: http.Server | false, secureServer?: http.Server | false,
  handler?: Handler) : Promise<{ server?: http.Server, secureServer?: http.Server }>
serve(options?: ServerOptions): void

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Lint and test your code.

License

Copyright (c) 2022-2024 Ferdinand Prantl

Licensed under the MIT license.