The Source Code For Depack's JavaScript API.
npm install @depack/depack
@depack/depack is The Source Code For Depack's JavaScript API. _Depack_ is the compiler of _Node.JS_ packages into a single executable, as well as the bundler for JavaScript web files using _Google Closure Compiler_. It scans the entry files to detect all dependencies, to passes them to _GCC_.
``sh`
yarn add @depack/depack
- Table Of Contents
- API
- async run(args, opts=): string
* RunConfig
- async Compile(options, runOptions=, compilerArgs=): string
* CompileConfig
- async Bundle(options, runOptions=, compilerArgs=): string
* BundleBase
* BundleConfig
- async BundleChunks(options, runOptions=, compilerArgs=): string
* ChunksConfig
* Caching
- getOptions(options): !Array
* GetOptions
- getOutput(output, src): string
- GOOGLE_CLOSURE_COMPILER: string
- async getCompilerVersion(): string
- License & Copyright
The package is available by importing its named functions:
![]() Compile, Bundle, BundleChunks, run, getOptions, getOutput, GOOGLE_CLOSURE_COMPILER, getCompilerVersion, ![]() |
async run(
opts=: !RunConfig,
): string and Bundle. Spawns _Java_ and executes the compilation. To debug a possible bug in the _GCC_, the sources after each pass can be saved to the file specified with the debug command. Also, _GCC_ does not add // # sourceMappingURL=output.map comment, therefore it's done by this method. Returns stdout of the _Java_ process. Returns the _stdout_ of the Java process. - args* !Array<string>: The arguments to Java.
- opts !RunConfig (optional): General options for running of the compiler.
RunConfig__: General options for running of the compiler.
Name
Type & Description
Default
output
string
-
The path where the output will be saved. Prints to stdout if not passed.
debug
string
-
The name of the file where to save sources after each pass. Useful when there's a potential bug in GCC.
compilerVersion
string
-
Used in the display message. Obtained with the getCompilerVersion method.
noSourceMap
boolean
false
Disables source maps.
async Compile(
options: !CompileConfig,
runOptions=: !RunConfig,
compilerArgs=: !Array
): string
Compiles a _Node.JS_ source file with dependencies into a single executable (with the +x addition). Performs regex-based static analysis of the whole of the dependency tree to construct the list of JS files. If any of the files use require, adds the --process_common_js_modules flag. Returns the stdout of the compiler, and prints to the console if output is not given in runOptions. - options* !CompileConfig: Options for the _Node.JS_ package compiler. Must have the
src prop at least.
- runOptions !RunConfig (optional): General options for running of the compiler.
- compilerArgs !Array<string> (optional): The compiler args got with getOptions and/or manually extended. getOptions needs to be called first to find out the compiler's JAR at minimum.The actual logic that makes compilation of _Node.JS_ packages possible is:
- Scan the source code and dependency to find out what internal Node.JS modules are used, and creates the output wrapper with
require calls to require those built-in modules, e.g., const path = require('path').
- Add appropriate externs for the internal modules.
- To make Closure resolve internal imports like import { join } from 'path' instead of throwing an error, mock the built-ins in node_modules folder. The mocks will reference the variable from the output wrapper generated in step 1:
`js
// node_modules/path/index.js
export default path
export * from path
`The last argument,
compilerArgs can come from the getOptions method. The output property should come from getOutput method to enable saving to directories without specifying the output filename (_GCC_ will do it automatically, but we need to write source maps and set +x).CompileConfig__: Options for the Node.JS package compiler.
Name
Type & Description
Default
src*
string
-
The entry file to bundle. Currently only single files are supported.
noStrict
boolean
false
Removes use strict from the output.
verbose
boolean
false
Print all arguments to the compiler.
silent
boolean
false
If output is not given, don't print to stdout. By default, the output will be printed.
library
boolean
false
Whether to create a library.
_For example, given the following source:_
Click to expand/collapse
`js
import { constants } from 'os'
import { createWriteStream, createReadStream } from 'fs'
// ...
`
`js
;(async () => {
const result = await new Promise((r, j) => {
const input = process.env['INPUT'] || __filename
const output = process.env['OUTPUT']
const rs = createReadStream(input)
const ws = output ? createWriteStream(output) : process.stdout
rs.pipe(ws)
rs.on('error', (err) => {
if (err.errno === -constants.errno.ENOENT) {
return j(Cannot find file ${input})
}
return j(err)
})
rs.on('close', () => {
r({ input, 'output': output })
})
})
const res = {
version: process.version,
...result,
}
console.log(res)
})()
`
_The library can be used to start the compilation:_
`js
import { getCompilerVersion, Compile, getOptions } from '@depack/depack'(async () => {
const compilerVersion = await getCompilerVersion()
const options = getOptions({
advanced: true,
prettyPrint: true,
languageIn: 2018,
languageOut: 2017,
})
await Compile({
src: 'example/compile-src.js',
}, { compilerVersion }, options)
})()
`_The compiled output in pretty format of advanced optimisation:_
`js
#!/usr/bin/env node
'use strict';
const os = require('os');
const fs = require('fs');
const g = os.constants;
const h = fs.createReadStream, k = fs.createWriteStream;
(async() => {
var d = await new Promise((l, e) => {
const a = process.env.INPUT || __filename, b = process.env.OUTPUT, c = h(a), m = b ? k(b) : process.stdout;
c.pipe(m);
c.on("error", f => f.errno === -g.errno.ENOENT ? e(Cannot find file ${a}) : e(f));
c.on("close", () => {
l({input:a, output:b});
});
});
d = Object.assign({}, {version:process.version}, d);
console.log(d);
})();
`_Stderr:_
java -jar /Users/zavr/node_modules/google-closure-compiler-java/compiler.jar \
--compilation_level ADVANCED --language_in ECMASCRIPT_2018 --language_out \
ECMASCRIPT_2017 --formatting PRETTY_PRINT --package_json_entry_names module,main \
--entry_point example/compile-src.js --externs node_modules/@externs/nodejs/v8/os.js \
--externs node_modules/@externs/nodejs/v8/fs.js --externs \
node_modules/@externs/nodejs/v8/stream.js --externs \
node_modules/@externs/nodejs/v8/events.js --externs \
node_modules/@externs/nodejs/v8/url.js --externs \
node_modules/@externs/nodejs/v8/global.js --externs \
node_modules/@externs/nodejs/v8/global/buffer.js --externs \
node_modules/@externs/nodejs/v8/nodejs.js
Built-ins: os, fs
Running Google Closure Compiler 20200112
async Bundle(
options: !BundleConfig,
runOptions=: !RunConfig,
compilerArgs=: !Array
): string
Bundles the browser source code into a _JavaScript_ file. If there are any _JSX_ dependencies, the bundler will transpile them first using ÀLaMode/JSX. Returns the stdout of the compiler, and prints to the console if output is not given in runOptions. - options* !BundleConfig: Options for the web bundler. Must have the
src prop at least.
- runOptions !RunConfig (optional): General options for running of the compiler.
- compilerArgs !Array<string> (optional): The compiler args got with getOptions and/or manually extended.BundleBase__: Options for the web bundler.
Name
Type & Description
Default
tempDir
string
depack-temp
Where to save prepared JSX files.
preact
boolean
false
Adds import { h } from 'preact' automatically, so that the bundle will be compiled together with Preact.
silent
boolean
false
If output is not given, don't print to stdout. By default, the output will be printed.
preactExtern
boolean
false
Adds import { h } from '@preact/extern' automatically, assuming that preact will be available in the global scope and won't be included in the compilation. It will also rename any preact imports into @externs/preact, so that the actual source code does not need manual editing.
BundleConfig extends BundleBase__: Options for the Bundle method.
Name
Type & Description
src*
string
The entry file to bundle. Only a single file is accepted. To compile multiple files at once, use chunks.
_For example, given the following single JS source:_
`js
/ eslint-env browser /
[...document.querySelectorAll('.BananaInactive')]
.forEach((el) => {
const parent = el.closest('.BananaCheck')
el.onclick = () => {
parent.classList.add('BananaActivated')
}
})
;[...document.querySelectorAll('.BananaActive')]
.forEach((el) => {
const parent = el.closest('.BananaCheck')
el.onclick = () => {
parent.classList.remove('BananaActivated')
}
})
`_Depack is used to make a JS file in ES2015 understood by old browsers:_
`js
import { getCompilerVersion, Bundle, getOptions } from '@depack/depack'(async () => {
const compilerVersion = await getCompilerVersion()
const options = getOptions({
advanced: true,
prettyPrint: true,
})
await Bundle({
src: 'example/bundle-src.js',
}, { compilerVersion }, options)
})()
`_The bundled output:_
`js
function c(a) {
var b = 0;
return function() {
return b < a.length ? {done:!1, value:a[b++]} : {done:!0};
};
}
function e(a) {
if (!(a instanceof Array)) {
var b = "undefined" != typeof Symbol && Symbol.iterator && a[Symbol.iterator];
a = b ? b.call(a) : {next:c(a)};
for (var d = []; !(b = a.next()).done;) {
d.push(b.value);
}
a = d;
}
return a;
}
e(document.querySelectorAll(".BananaInactive")).concat().forEach(function(a) {
var b = a.closest(".BananaCheck");
a.onclick = function() {
b.classList.add("BananaActivated");
};
});
e(document.querySelectorAll(".BananaActive")).concat().forEach(function(a) {
var b = a.closest(".BananaCheck");
a.onclick = function() {
b.classList.remove("BananaActivated");
};
});
`_Stderr:_
java -jar /Users/zavr/node_modules/google-closure-compiler-java/compiler.jar \
--compilation_level ADVANCED --formatting PRETTY_PRINT
--js example/bundle-src.js
Running Google Closure Compiler 20200112
async BundleChunks(
options: !ChunksConfig,
runOptions=: !RunConfig,
compilerArgs=: !Array
): string
Bundles the browser source code into multiple _JavaScript_ file. Works in the same way as Bundle, generating a temp dir for JSX dependencies. - options* !ChunksConfig: Options for the web bundler. Must have the
srcs prop with paths to source files at least.
- runOptions !RunConfig (optional): General options for running of the compiler.
- compilerArgs !Array<string> (optional): The compiler args got with getOptions and/or manually extended.ChunksConfig extends BundleBase__: Options for the BundleChunks method.
Name
Type & Description
srcs*
!Array<string>
The entry files to bundle. Chunks will be created according to the strategy (only common strategy is supported at the moment, which places any dependency which is required in more than one file in a common chunk).
rel*
string
Directory to which sources of chunks are relative. By default, the basenames are used for chunk names, but if sources are from multiple dirs, this prop can be set. Because chunk names cannot contain /, separators will be substituted for -. For example, given the following input:
src/lib.js
src/source1.js
src/dir/source2.js and using rel=src, the following chunks are created:
lib
source1
dir-source2
checkCache
(analysis: !Array<!_staticAnalysis.Detection>) => !Promise<(boolean | undefined)>
A function to be executed to compare the an existing static analysis result with the new one, to see if any files/dependencies were updated. Should return true when caches match to skip processing and return void.
analysis* !Array<!_staticAnalysis.Detection>: New static analysis result.
_For example, given the following multiple JS sources:_
Click to expand/collapse
`js
// chunkA.js
import test from './'
import { common } from './common'
console.log('chunk a')
test()
common()
`
...
`js
// chunkB.js
import test from './'
import { common } from './common'
console.log('chunk b')
test()
common()
`
`js
// common.js
export const common = (opts = {}) => {
const { a } = opts
if (window.DEBUG && a) console.log('test')
}
`
`js
// index.js
export default () => {
console.log('common')
}
`
_Depack can generate multiple output files when a number of entries are passed:_
`js
const options = getOptions({
chunkOutput: TEMP,
advanced: true,
sourceMap: false,
})
await BundleChunks({
silent: true,
srcs: ['test/fixture/chunks/chunkA.js',
'test/fixture/chunks/chunkB.js'],
}, { output: TEMP, noSourceMap: true }, options)
`_The bundled output:_
`js
chunkA.js
console.log("chunk a");console.log("common");c();
chunkB.js
console.log("chunk b");console.log("common");c();
common.js
function c(){var a=void 0===a?{}:a;a=a.a;window.b&&a&&console.log("test")};
`_Stderr:_
java -jar /Users/zavr/node_modules/google-closure-compiler-java/compiler.jar \
--compilation_level ADVANCED --chunk_output_path_prefix test/temp/ --module_resolution \
NODE
--js test/fixture/chunks/index.js
test/fixture/chunks/common.js
--chunk common:2
test/fixture/chunks/chunkA.js
--chunk chunkA:1:common
test/fixture/chunks/chunkB.js
--chunk chunkB:1:common
Running Google Closure Compiler
$3
This method supports caching. It will shallowly analyse source files (does not go into
node_modules apart from finding out their version), and run the checkCache function if it was passed. If this callback returns true, the compilation will be skipped. See an example implementation below.`js
import stat from 'async-stat'
import deepEqual from '@zoroaster/deep-equal'
import { BundleChunks } from '../src'const compileOurChunks = async (srcs) => {
let cachedMap, needsCacheUpdate
let map = await BundleChunks({
srcs,
preactExtern: true,
async checkCache(analysis) {
// somehow get the cache object: { chunksMap, files, deps }
const { chunksMap, ...current } = splendid.getCache('compile-comps')
cachedMap = chunksMap
const deps = {}
const entries = []
analysis.forEach(({ name, version, entry }) => {
if (name) deps[name] = version
else entries.push(entry)
})
const files = await entries.reduce(async (acc, file) => {
const accRes = await acc
/* @type {import('fs').Stats} /
const ls = await stat(file)
const d = new Date(ls.mtimeMs).toLocaleString()
accRes[file] = d
return accRes
}, {})
try {
deepEqual({ files, deps }, current, ' ')
// this is now OK, should not need to do anything else
splendid.log2('compile-comps', 'Comps not changed.')
return true
} catch (err) {
splendid.log2('compile-comps', err.message)
needsCacheUpdate = err.actual
}
},
}, { compilerVersion, output }, options)
if (needsCacheUpdate) {
needsCacheUpdate.chunksMap = map
// save new cache: { chunksMap, files, deps }
await splendid.appendCache('compile-comps', needsCacheUpdate)
} else if (!map) {
map = cachedMap
}
return map
}
`getOptions(
options: !GetOptions,
): !Array
Returns an array of options to pass to the compiler for Compile, Bundle and BundleChunks methods. Full list of supported arguments. - options* .">!GetOptions: The map of options to be converted into Java arguments.
GetOptions__: Parameters for getOptions.
Name
Type & Description
Default
compiler
string
-
The path to the compiler JAR. Default value will be got from require.resolve('google-closure-compiler-java/compiler.jar').
output
string
-
Sets the --js_output_file flag.
chunkOutput
string
-
Sets the --chunk_output_path_prefix flag.
level
string
-
Sets the --compilation_level flag.
advanced
boolean
false
Sets the --compilation_level flag to ADVANCED.
languageIn
(string | number)
-
Sets the --language_in flag. If a year is passed, adjusts it to ECMASCRIPT_{YEAR} automatically.
languageOut
(string | number)
-
Sets the --language_out flag. If a number is passed, adjusts it to ECMASCRIPT_{YEAR} automatically.
sourceMap
boolean
true
Adds the --create_source_map %outname%.map flag.
prettyPrint
boolean
false
Adds the --formatting PRETTY_PRINT flag.
iife
boolean
false
Adds the --isolation_mode IIFE flag.
noWarnings
boolean
false
Sets the --warning_level QUIET flag.
debug
string
-
The location of the file where to save sources after each pass. Disables source maps as these 2 options are incompatible.
argv
!Array<string>
-
Any additional arguments to the compiler.
Example:
Click to show/hide output`js
import { getOptions } from '@depack/depack'
const opts = getOptions({
advanced: true,
iife: true,
languageIn: 2019,
languageOut: 2017,
noWarnings: true,
prettyPrint: true,
output: 'bundle.js',
argv: ['--externs', 'externs.js'],
})
console.log(opts)
`
---
`js
[ '-jar',
'/Users/zavr/node_modules/google-closure-compiler-java/compiler.jar',
'--compilation_level',
'ADVANCED',
'--language_in',
'ECMASCRIPT_2019',
'--language_out',
'ECMASCRIPT_2017',
'--create_source_map',
'%outname%.map',
'--formatting',
'PRETTY_PRINT',
'--isolation_mode',
'IIFE',
'--warning_level',
'QUIET',
'--externs',
'externs.js',
'--js_output_file',
'bundle.js' ]
`
getOutput(
output: string,
src: string,
): string
Returns the location of the output file, even when the directory is given. - output*
string: The path to the output dir or file.
- src* string: The path to the source file. Will be used when the output is a dir.`js
import { getOutput } from '@depack/depack'const file = getOutput('output/example.js', 'src/example.js')
console.log('File: %s', file)
const dir = getOutput('output', 'src/index.js')
console.log('Dir: %s', dir)
`
`js
File: output/example.js
Dir: output/index.js
`GOOGLE_CLOSURE_COMPILER: stringIf the
GOOGLE_CLOSURE_COMPILER was set using the environment variable, it will be returned in this named exported.async getCompilerVersion(): string
If GOOGLE_CLOSURE_COMPILER was set using an environment variable, returns target, otherwise reads the version from the google-closure-compiler-java` package.json file.GNU Affero General Public License v3.0
alt="Art Deco"> | © Art Deco™ for Depack 2020 |
|---|