Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Aug 5, 2017
0 parents commit 48a21e9
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.DS_Store
yarn.lock
14 changes: 14 additions & 0 deletions packages/core/parcel-bundler/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "bundler1",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"babel-core": "^6.25.0",
"babylon": "^6.17.4",
"babylon-walk": "^1.0.2",
"browser-resolve": "^1.11.2",
"node-libs-browser": "^2.0.0",
"worker-farm": "^1.4.1"
}
}
60 changes: 60 additions & 0 deletions packages/core/parcel-bundler/src/Bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const fs = require('./utils/fs');
const Module = require('./Module');
const Resolver = require('./Resolver');
const Parser = require('./Parser');
const workerFarm = require('worker-farm');
const promisify = require('./utils/promisify');

class Bundle {
constructor(main, options) {
this.mainFile = main;
this.options = options;
this.resolver = new Resolver(options);
// this.parser = new Parser(options);

this.loadedModules = new Map;
this.loading = new Set;
this.farm = workerFarm({autoStart: true},require.resolve('./worker.js'));
this.runFarm = promisify(this.farm);
}

async collectDependencies() {
let main = await this.resolveModule(this.mainFile);
await this.loadModule(main);
console.log('done')
workerFarm.end(this.farm);
return main;
}

async resolveModule(name, parent) {
let path = await this.resolver.resolve(name, parent);
if (this.loadedModules.has(path)) {
return this.loadedModules.get(path);
}

let module = new Module(path, this.options);
this.loadedModules.set(path, module);
return module;
}

async loadModule(module) {
if (this.loading.has(module)) {
return;
}

this.loading.add(module);

let deps = await this.runFarm(module.name, this.options);

module.dependencies = deps;
// module.ast = ast;

await Promise.all(deps.map(async dep => {
let mod = await this.resolveModule(dep, module.name);
module.modules.set(dep, mod);
await this.loadModule(mod);
}));
}
}

module.exports = Bundle;
32 changes: 32 additions & 0 deletions packages/core/parcel-bundler/src/Module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const traverse = require('babel-traverse').default;
const types = require('babel-types');
const path = require('path');
const collectDependencies = require('./visitors/dependencies');
const walk = require('babylon-walk');

class Module {
constructor(name, options = {}) {
this.name = name;
this.basename = path.basename(this.name, path.extname(this.name));
this.code = null;
this.ast = null;
this.options = options;

this.dependencies = new Set;
this.modules = new Map;
}

async load() {

}

traverse(visitor) {
return walk.simple(this.ast, visitor, this);
}

collectDependencies() {
this.traverse(collectDependencies);
}
}

module.exports = Module;
46 changes: 46 additions & 0 deletions packages/core/parcel-bundler/src/Parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const path = require('path');
const es6 = require('./parsers/es6');
const json = require('./parsers/json');

class Parser {
constructor(options = {}) {
this.extensions = {};

let extensions = options.extensions || {};
for (let ext in extensions) {
this.registerExtension(ext, extensions[ext]);
}

this.registerExtension('.js', es6);
this.registerExtension('.jsx', es6);
this.registerExtension('.es6', es6);
this.registerExtension('.json', json);
}

registerExtension(ext, parser) {
if (typeof parser === 'string') {
parser = require(parser);
}

this.extensions[ext] = parser;
}

findParser(filename) {
let extension = path.extname(filename);
let parser = this.extensions[extension];
if (!parser) {
throw new Error('Could not find parser for extension ' + extension);
}

return parser;
}

parse(filename, code) {
let parser = this.findParser(filename);
let options = Object.assign({filename: filename}, this.options);
// console.log('parsing', filename)
return parser(code, options);
}
}

module.exports = Parser;
41 changes: 41 additions & 0 deletions packages/core/parcel-bundler/src/Resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const promisify = require('./utils/promisify');
// const builtins from './builtins';
// import _resolve from 'browser-resolve';
const resolve = promisify(require('browser-resolve'));
const builtins = require('node-libs-browser');
const path = require('path');

for (let key in builtins) {
if (builtins[key] == null) {
builtins[key] = require.resolve('./_empty.js');
}
}

class Resolver {
constructor(options = {}) {
this.options = options;
this.cache = new Map;
}

async resolve(filename, parent) {
let key = (parent ? path.dirname(parent) : '') + ':' + filename;
if (this.cache.has(key)) {
// console.log('cached!', key)
return this.cache.get(key);
}

var res = await resolve(filename, {
filename: parent,
paths: this.options.paths,
modules: builtins
});

if (Array.isArray(res))
res = res[0];

this.cache.set(key, res);
return res;
}
}

module.exports = Resolver;
Empty file.
38 changes: 38 additions & 0 deletions packages/core/parcel-bundler/src/builtins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
exports.assert = require.resolve('assert/');
exports.buffer = require.resolve('buffer/');
exports.child_process = require.resolve('./_empty.js');
exports.cluster = require.resolve('./_empty.js');
exports.console = require.resolve('console-browserify');
exports.constants = require.resolve('constants-browserify');
exports.crypto = require.resolve('crypto-browserify');
exports.dgram = require.resolve('./_empty.js');
exports.dns = require.resolve('./_empty.js');
exports.domain = require.resolve('domain-browser');
exports.events = require.resolve('events/');
exports.fs = require.resolve('./_empty.js');
exports.http = require.resolve('stream-http');
exports.https = require.resolve('https-browserify');
exports.module = require.resolve('./_empty.js');
exports.net = require.resolve('./_empty.js');
exports.os = require.resolve('os-browserify/browser.js');
exports.path = require.resolve('path-browserify');
exports.punycode = require.resolve('punycode/');
exports.querystring = require.resolve('querystring-es3/');
exports.readline = require.resolve('./_empty.js');
exports.repl = require.resolve('./_empty.js');
exports.stream = require.resolve('stream-browserify');
exports._stream_duplex = require.resolve('readable-stream/duplex.js');
exports._stream_passthrough = require.resolve('readable-stream/passthrough.js');
exports._stream_readable = require.resolve('readable-stream/readable.js');
exports._stream_transform = require.resolve('readable-stream/transform.js');
exports._stream_writable = require.resolve('readable-stream/writable.js');
exports.string_decoder = require.resolve('string_decoder/');
exports.sys = require.resolve('util/util.js');
exports.timers = require.resolve('timers-browserify');
exports.tls = require.resolve('./_empty.js');
exports.tty = require.resolve('tty-browserify');
exports.url = require.resolve('url/');
exports.util = require.resolve('util/util.js');
exports.vm = require.resolve('vm-browserify');
exports.zlib = require.resolve('browserify-zlib');
exports._process = require.resolve('process/browser');
27 changes: 27 additions & 0 deletions packages/core/parcel-bundler/src/parsers/es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const babylon = require('babylon');

module.exports = function (code, opts) {
const options = {
filename: opts.filename,
allowImportExportEverywhere: opts.loose,
allowReturnOutsideFunction: true,
allowHashBang: true,
ecmaVersion: Infinity,
strictMode: false,
sourceType: 'module',
locations: true,
features: opts.features || {},
plugins: opts.plugins || [
'asyncFunctions',
'asyncGenerators',
'classConstructorCall',
'classProperties',
'decorators',
'exportExtensions',
'jsx',
'flow'
]
};

return babylon.parse(code, options);
};
5 changes: 5 additions & 0 deletions packages/core/parcel-bundler/src/parsers/json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const es6 = require('./es6');

module.exports = function (code, opts) {
return es6('module.exports = ' + code + ';', opts);
};
5 changes: 5 additions & 0 deletions packages/core/parcel-bundler/src/utils/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const promisify = require('./promisify');
const fs = require('fs');

exports.readFile = promisify(fs.readFile);
exports.writeFile = promisify(fs.writeFile);
15 changes: 15 additions & 0 deletions packages/core/parcel-bundler/src/utils/promisify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = function(fn) {
return function(...args) {
return new Promise(function(resolve, reject) {
fn(...args, function(err, ...res) {
if (err)
return reject(err);

if (res.length === 1)
return resolve(res[0]);

resolve(res);
});
});
};
}
52 changes: 52 additions & 0 deletions packages/core/parcel-bundler/src/utils/queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class Queue {
constructor() {
this.q = new Map;
this.promises = new Map;
this.running = 0;
this.concurrency = 50;
}

add(key, fn) {
if (!this.q.has(key)) {
let promise = new Promise((resolve, reject) => {
this.q.set(key, {fn, resolve, reject});
this.run();
});

this.promises.set(key, promise);
return promise;
} else {
return this.promises.get(key);
}
}

run() {
while (this.running < this.concurrency && this.q.size > 0) {
this.processNext();
}
}

async processNext() {
if (this.q.size === 0) {
return;
}

let [key, {fn, resolve, reject}] = this.q.entries().next().value;
this.q.delete(key);

this.running++;

try {
let res = await fn();
resolve(res);
} catch (err) {
reject(err);
} finally {
this.running--;
this.promises.delete(key);
this.run();
}
}
}

module.exports = Queue;
32 changes: 32 additions & 0 deletions packages/core/parcel-bundler/src/visitors/dependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const types = require('babel-types');

module.exports = {
ImportDeclaration(node, module) {
module.dependencies.add(node.source.value);
},

ExportNamedDeclaration(node, module) {
if (node.source) {
module.dependencies.add(node.source.value);
}
},

ExportAllDeclaration(node, module) {
module.dependencies.add(node.source.value);
},

CallExpression(node, module) {
let {callee, arguments: args} = node;

let isRequire = types.isIdentifier(callee)
&& callee.name === 'require'
&& args.length === 1
&& types.isStringLiteral(args[0]);

if (!isRequire) {
return;
}

module.dependencies.add(args[0].value);
}
};
Loading

0 comments on commit 48a21e9

Please sign in to comment.