JSPM

  • Created
  • Published
  • Downloads 882
  • Score
    100M100P100Q101248F
  • License MIT

A regex-based transpiler of source code to allow writing import and export statements.

Package Exports

  • alamode

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (alamode) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

alamode

npm version

alamode is a RegExp-based transpiler of source code in Node.js. It is a fast, low-weight alternative to AST-based transpilers, such as @babel. At the moment, it supports transpilation of import and export statements which also improves JSDoc support compared to Babel.

yarn add -DE alamode

The package can be used via the CLI to build packages, or via the require hook to transform modules on-the-fly.

Table Of Contents

Installation

The software can be installed either as a global dependency, or as a project dependency.

Global

When installed globally, it will be used directly via a binary, such as alamode src -o build.

Package Manager Installation
npm npm i -g alamode
yarn yarn add global alamode

Project

When installed in a project, it will be used via the package.json script, e.g., yarn build or npm run build.

// package.json
{
  "name": "project",
  "version": "1.0.0",
  "description": "An example project",
  "main": "build",
  "scripts": {
    "build": "alamode src -o build"
  },
  "files": ["build"],
  "license": "MIT"
}
Package Manager Installation
npm npm i --save-dev alamode
yarn yarn add -DE alamode

CLI

The binary accepts a path to a single file, or a directory with the source code as the first argument, and a path to the build folder via -o argument.

alamode src -o build

There are other arguments which can be passed.

Property Argument Description
Output Location -o, --output Where to save transpiled code. Passing - will print to stdout.
Watch Mode -w, --watch Keep alamode running and re-build on chages.
Show Help -h, --help Display help information and quit.
Ignore Paths -i, --ignore A list of files inside of the source directory to ignore, separated with a comma. For example, to ignore src/bin/alamode.js when building src, the -i bin/alamode.js should be passed
No Source Maps -s, --noSourceMaps Don't generate source maps.
Extensions -e, --extensions Which extensions to transform, separated by a comma. Defaults are js and jsx.

Setting the NODE_DEBUG environmental variable to alamode will print the list of processed files to the stderr.

$ NODE_DEBUG=alamode alamode src -o build -i bin/alamode.js
ALAMODE 97955: index.js
ALAMODE 97955: bin/catcher.js
ALAMODE 97955: bin/index.js
ALAMODE 97955: lib/index.js

.alamoderc.json

A transform can support options which can be set in the .alamoderc.json configuration file which is read from the same directory where the program is executed. Options inside of the env directive will be active only when the ALAMODE_ENV environmental variable is set to the env key.

{
  "env": {
    "test-build": {
      "import": {
        "replacement": {
          "from": "^((../)+)src",
          "to": "$1build"
        }
      }
    }
  }
}

Transforms

There are a number of built-in transforms, which don't need to be installed separately because their size is small enough to be included as direct dependencies.

@a-la/import

Changes all import statements into require statements. Although the specification between the ECMAScript Modules and Modules is different, most developers will prefer to use import just because of its neater syntax.

import argufy from 'argufy'
import restream, {
  Replaceable,
  makeMarkers, makeCutRule, makePasteRule,
} from 'restream'
import { resolve, join } from 'path'
import { version } from '../../package.json'
let argufy = require('argufy'); if (argufy && argufy.__esModule) argufy = argufy.default;
let restream = require('restream'); if (restream && restream.__esModule) restream = restream.default; const {
  Replaceable,
  makeMarkers, makeCutRule, makePasteRule,
} = restream
const { resolve, join } = require('path');
const { version } = require('../../package.json');

The if (dependency && dependency.__esModule) dependency = dependency.default; check is there to make alamode compatible with Babel and TypeScript, which export default modules as the default property of module.exports object and set the __esModule marker to true, e.g.,

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = method;

Replace Path

This transform supports an option to replace the path to the required file using a regular expression. This can be useful when running tests against the build directory, rather than source directory.

{
  "import": {
    "replacement": {
        "from": "^((../)+)src",
          "to": "$1build"
      }
    }
  }
}
/* yarn example/ */
import alamode from '../src'

(async () => {
  await alamode()
})()
/* yarn example/ */
let alamode = require('../build'); if (alamode && alamode.__esModule) alamode = alamode.default;

(async () => {
  await alamode()
})()

@a-la/export

Transforms all export statements into module.exports statements.

Input Output
export async function example () {}

const example2 = () => {}

export default class Example {
  constructor() {
    example()
  }
}

export { example2 as alias }
async function example () {}

const example2 = () => {}

               class Example {
  constructor() {
    example()
  }
}



module.exports = Example
module.exports.example = example
module.exports.alias = example2

There are some limitations one should be aware about, however they will not typically cause problems for a Node.JS package. The line and column numbers are preserved for easier generation of the source maps, however this is likely to change in the future.

Require Hook

The purpose of the require hook is to be able to run transpile files automatically when they are imported.

To use this feature, alamode needs to be required in a separate file, after which import and export statements will become available.

For example, take the following directory structure, with a main and library files:

example/require
├── index.js
├── lib.js
└── require.js
index.js lib.js
import getInfo from './lib'

console.log(getInfo())
import { platform, arch } from 'os'

export default () => {
  return `${platform()}:${arch()}`
}

The require hook would work in the following way:

require('alamode')()
require('.')

By executing the node require.js command, alamode will be installed and it will do its job dynamically for every .js file that is required, enabling to use import and export statements.

darwin:x64

Source Maps

The source maps are supported by this package, but implemented in a hack-ish way. The transforms will aim to preserve line and column numbers, so that no additional remapping is required. However this is not enough to generate a source map good enough for a debugger -- it needs to know about mappings of positions between segments which can be operators, function calls, etc. alamode simply breaks the source code into distinct chunks such as white-spaces, identifiers and comments, and down into individual symbols. Using this method, the size of a source map is larger, but it still works. In further versions, this will be improved to allow to extract real segments.

source map visualistion

Click to View: debug session
Alt: Debugging a source code with source maps.

Troubleshooting

Because there can be many intricacies when transpiling with regular expressions, problems might arise from time to time. If using the require hook, the best solution is to build the source code using alamode binary, and see where the error occurs. Then it must be analysed why it happens, for example:

  • The import or export transform does not match the case.
  • A portion of source code is cut out before the transform with markers so that the line does not participate in a transform.

TODO

  • Allow to erase the build directory before the build so that old files are removed.
  • Implement JSX transform.
  • Dynamic mode when code is evaluated to find when transforms are required (target).

(c) À La Mode 2018