4.1.21-a • Published 3 months ago

neo-builder v4.1.21-a

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

neo-builder

npm npm

The simplest javascript builder based on regular expressions, started as research project

Features:

  • Lite weight (less then 6 kb zipped)
  • Iife wrapping of each modules (without dublicating)
  • Support of node_modules (reexports, direct imports from node-modules, etc)
  • Dynamic imports iife support with common modules shareing
  • Supports variables in dynamic imports (via template strings) out of the box (look up limitaions)
  • fast build speed (commensurate with esbuild or vite in release mode).
  • particullary pnpm support
  • tree shaking (now it is only for function expressions) with esm and cjs support (but still w/o deep diving)

Benchmarks

Benchmarks of various popular bundlers for random packages:

packagewebpackneo-builderesbuildparcel
@uppy/dashboard1272ms67ms47ms-
@codemirror/lang-javascript1513ms70ms68ms75ms
codemirror1520ms77ms72ms81ms
msw1179ms32ms48ms265ms
swiper911ms26ms27ms86ms

Bundle sizes

A comparative table of the sizes of the received bundles allows us to indirectly draw conclusions about the quality of the builder's three shaking feature:

packagewebpackneo-builder*esbuildparcel
@uppy371 kb382 kb346 kb-
@codemirror-javascript1016 kb1040 kb649 kb942 kb
codemirror1007 kb1034 kb751 kb942 kb
msw85 kb72 kb66 kb1184 kb
swiper303 kb170 kb166 kb342 kb

The same packages minified: @uppy/dashboard | 181kb | 182kb | 179kb | - @codemirror/lang-javascript | 326kb | 360kb | 322kb | 433kb codemirror | 344kb | 344kb | 338kb | 391kb | msw | 27kb | 22kb | 27kb | error swiper | 77kb | 75kb | 75kb | 164kb

  • */ was used fast mode of tree shaking

Issues:

  • Doesn't support some difficult imports (for example the module and default import in one line, like this: import * as module, defaultImport from 'module') because of unuselessness. At last what is the reason to import default when module at the same time consists of the default?)
  • Tree shaking in a progress (just shallow experimental tree-shaking)
  • Incremental mode in a progress (may be, will not be done)
  • Does not create meaningful AST tree. So it can easily break down where linter is not used or complex strings and nested structures are used in the exports

Installation:

local

npm i neo-builder -D --omit=dev

or global

npm i neo-builder -g

Usage via cli:

neo index.js -t target.js --time

Possible options:

  • -s - source file name (could be passed as first arg without the flag -s)
  • -t - target file name (required)
  • -m - generate sourcemap file (optional)
  • --time - verbose build time (optional)

Usage via api:

const packFile = require('neo-builder').packFile
let r = packFile(sourceFile, targetFile, {
    // options
});

Possible options:

  • release? - remove one line comments and plain console.log expressions
  • purgeDebug? - remove /**@debug*/ ... /**@end_debug*/ code blocks
  • getContent? - custom getContent implementation
  • logStub? - logs with source filename and line in runtime
  • sourceMaps?: { encode: Function, external?: true } - option for source map passing the encode method from the sourcemap-codec library or its independent implementation. Look tests for example
  • getSourceMap?: Function - an alternative method for obtaining unencrypted line-by-line source maps for its further programmatic use (works 30% faster than the classical generation of char by char sourcemaps)

build example:

__common.ts file:

let r = 7
function asd(){}

export let months = ['Jan', 'Feb', 'Mar', 'Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
export var a = 6;
export function Ads(arg){}
export class Asde{}

and init.ts:

import * as com from "./__common"

var a = com.a;
var c = 7540;

turn out the content inside init.js in the same directory:

//@modules:


const $$__commonExports = (function (exports) {
 let r = 7
	function asd() { }
	
	let months = ['Jan', 'Feb', 'Mar', 'Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
	var a = 6;
	function Ads(arg) { }
	class Asde { }
	
	exports = { months, a, Ads, Asde };
	
	return exports 
})({})


//@init.ts: 
const com = $$__commonExports;

var a = com.a;
var c = 7540;

Code Splitting

Neo-builder supports dynamic imports (with iife) under browser mode out of the box, what makes it unique. Let's consider the following code:

const langs = ['python', 'javascript'];
for (const key in langs) {
    const lang = langs[key];
    import(`@codemirror/lang-${lang}`).then(exp => {
        console.log(exp[lang]());
    })
}

It'll be built into the following code:

const langs = ['python', 'javascript'];
for (const key in langs) {
    const lang = langs[key];
    fetch(`./dist/$_lang-${lang}_1702744262895.js`).then(r => r.text()).then(content => new Function(content)()).then(exp => {
        console.log(exp[lang]());
    })
}

Simultaneously it'll build relevant files into the distination folder ($_lang-javascript_1702744262895.js and $_lang-python_1702744262895.js). But be careful: this files will be created at the same folder where main app file is built. If you want to manage path, specified into the fetch request, you should use advanced.dynamicImportsRoot option in your build config.

As you can see, in the example above it is used variable inside template string. Neo-builder supports variables by dynamic imports out of the box and allows import packages directly from node_modules. These features also unique feature at this time (mainstream builders haven't variables support out of the box, and direct imports from node_modules haven't support, at all). But you should be awared there are limitations of the usage:

  • Package name format, specified in the import, should have at least two chars on left or right side from variable insertion. That's way to be sure you know what you do. (now this rule refers just to direct imports, not to relative ones.)
  • No more then ten packages recommended to be matched corresponding pattern (else you'll get apropriate warning)

Tree shaking

Tree shaking cuts unused functions from code bundle. But by default is disabled (because of in alpha). To use it, set advanced.treeShaking option into true.

Consider following files:

app.js:

import { default as A } from "./routes";
console.log(A)

routes.js

function _func(params) {
    return params.length
}

export function func() {
    return _func(arguments);
}

function createArray(length) {
    return Array(length)
}

export default function() {
    return createArray(0);
}

With enabled treeShaking unused functions _func and func will be cutted in the resulting bundle:

const $__routesExports = (function (exports) {
	function createArray(length) {
	    return Array(length)
	}
	
	function $default() {
	    return createArray(0);
	}
	
	exports = { default: $default };
	
	return exports 
})({})

Plugins usage:

neo-builder also supports custom plugins. Below there is example how itcan be used:

const uglify = require("uglify-js");

const neoMinify = {
	name: 'neo-minify-plugin',
	bundle: (/** @type {string} */ code, { maps, rawMap }) => {            
		const result = uglify.minify({ target: code }, {
			sourceMap: sourcemap ? {
				content: JSON.stringify(maps),
				url: sourcemapInline ? "inline" : (target + ".map")
			} : undefined
		});

		if (sourcemap && !sourcemapInline) {
			fs.writeFileSync(target + '.map', result.map)
			// fs.writeFileSync(target + '.map', JSON.stringify(result.map))
		}

		return result.code
	}
}


let r = packFile(sourceFile, targetFile, {
    // options
	plugins: [neoMinify]
});	
4.1.15-a

4 months ago

4.1.19-a

3 months ago

4.1.21-a

3 months ago

4.1.14-a

4 months ago

4.1.18-a

3 months ago

4.1.17-a

4 months ago

4.1.16-a

4 months ago

4.1.11-a

9 months ago

4.1.8-a

9 months ago

4.1.10-a

9 months ago

4.1.9-a

9 months ago

4.1.13-a

9 months ago

4.1.12-a

9 months ago

4.1.7-a

1 year ago

4.1.3-a

1 year ago

4.1.5-a

1 year ago

4.1.4-a

1 year ago

4.1.6-a

1 year ago

4.1.1-a

1 year ago

4.1.2-a

1 year ago

4.0.4-a

1 year ago

4.1.0-a

1 year ago

4.0.3-a

1 year ago

4.0.2-a

1 year ago

4.0.0-a

1 year ago

3.2.0-a

1 year ago

3.1.11-a

1 year ago

3.1.10-a

1 year ago

3.1.12-a

1 year ago

3.1.8-a

2 years ago

3.1.7-a

2 years ago

3.1.9-a

2 years ago

3.1.6-a

2 years ago

3.1.4-a

2 years ago

3.1.2-a

2 years ago

3.1.0-a

2 years ago

3.1.5-a

2 years ago

3.1.3-a

2 years ago

3.0.6-a

2 years ago

3.0.7-a

2 years ago

3.0.4-a

2 years ago

3.0.3-a

2 years ago

3.0.5-a

2 years ago

3.0.1-a

2 years ago

2.2.18-b

2 years ago

2.2.17

2 years ago

2.2.18

2 years ago

2.2.15

2 years ago

2.2.16

2 years ago

2.2.13

2 years ago

2.2.14

2 years ago

2.2.19

2 years ago

2.2.28

2 years ago

2.2.29

2 years ago

2.2.26

2 years ago

2.2.27

2 years ago

2.2.24

2 years ago

2.2.25

2 years ago

2.2.22

2 years ago

2.2.21

2 years ago

2.2.39

2 years ago

2.2.37

2 years ago

2.2.38

2 years ago

2.2.35

2 years ago

2.2.36

2 years ago

2.2.33

2 years ago

2.2.34

2 years ago

2.2.31

2 years ago

2.2.32

2 years ago

2.2.30

2 years ago

2.2.44

2 years ago

2.2.45

2 years ago

2.2.42

2 years ago

2.2.40

2 years ago

2.2.41

2 years ago

2.2.1

2 years ago

2.2.11

2 years ago

2.2.12

2 years ago

2.2.10

2 years ago

2.1.21

2 years ago

2.1.20

2 years ago

2.1.19

2 years ago

2.1.18

2 years ago

2.1.17

2 years ago

2.1.16

2 years ago

2.0.15

2 years ago

2.0.14

2 years ago

2.0.13

2 years ago

2.0.12

2 years ago

2.0.11

2 years ago

2.0.10

2 years ago

2.0.91

2 years ago

2.0.9

2 years ago

2.0.8

2 years ago

2.0.7

2 years ago

2.0.6

2 years ago

2.0.5

2 years ago

2.0.4

2 years ago

2.0.3

2 years ago

2.0.2

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago