Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

easy life #4

Open
jeremy-coleman opened this issue Sep 26, 2019 · 0 comments
Open

easy life #4

jeremy-coleman opened this issue Sep 26, 2019 · 0 comments

Comments

@jeremy-coleman
Copy link

jeremy-coleman commented Sep 26, 2019

enableLegacyBabel5ModuleInterop: true is good with browserify
there's a prod mode setting for sucrase also, i suppose its a free envify
at least 10x less memory use than webpack, sadly that a true statement lol

var stream = require("stream");
var util   = require("util");
var path   = require("path");

let sucrase = require("sucrase")

module.exports = buildTransform();
module.exports.configure = buildTransform;



/** @type import('sucrase').Options */
var sucraseConfig = file => ({
  transforms: ["typescript", "imports", "jsx"],
  filePath: file,
  //enableLegacyTypeScriptModuleInterop: true
  enableLegacyBabel5ModuleInterop: true
})

/** @type import('sucrase').Options */
var sucraseHotConfig = file => ({
  transforms: ["typescript", "imports", "jsx", "react-hot-loader"],
  filePath: file,
  //enableLegacyTypeScriptModuleInterop: true
  enableLegacyBabel5ModuleInterop: true
})

function buildTransform() {
  return function (filename) {
    const babelOpts = sucraseConfig(filename)
    if (babelOpts === null) {
      return stream.PassThrough();
    }
    return new SucraseStream(babelOpts);
  };
}

class SucraseStream extends stream.Transform {
  constructor(opts) {
    super();
    this._data = [];
    this._opts = opts;
  }

  _transform(buf, enc, callback) {
    this._data.push(buf);
    callback();
  }

  _flush(callback) {
    // Merge the buffer pieces after all are available
    const data = Buffer.concat(this._data).toString();

    try{
      let result = sucrase.transform(data, this._opts)
      var code = result !== null ? result.code : data;
      this.push(code);
      callback();
    }
    catch(e){
      callback(e)
    }
  }
}

you can use this to auto alias everything in src (or wherever, easy to change) so you can use absolute paths np. I suppose you could do some charCode string checks for 'react' to replace with 'preact' or something like that, but meh.

var path = require('path')
const { Transform, PassThrough } = require('stream')

/** type{(file: ReadonlyArray<string>, dir: string)}*/
function parseImports(file, dir) {
  const results = file.map((line, index) => {
    const imports = findImport(line);

    if (imports === null) {
      return null;
    }

    return {
      path: dir,
      index,
      import: imports,
    };
  });

  return results.filter((value) => {
    return value !== null && value !== undefined;
  });
}

/** 
 * @type{(line: string)}
 * @returns {string | null}
*/
function findImport(line) {
  const matches = line.match(/from (["'])(.*?)\1/) || line.match(/import\((["'])(.*?)\1\)/) || line.match(/require\((["'])(.*?)\1\)/);

  if (!matches) {
    return null;
  }

  const multiple = [/from (["'])(.*?)\1/g, /import\((["'])(.*?)\1\)/g, /require\((["'])(.*?)\1\)/g].some((exp) => {
    const results = line.match(exp);

    //console.log(results)
    //
    //return results && results.length > 1

    if (results && results.length > 1) {
      results.map(r => findImport(r))
    }
  })

 // if (multiple) {
    //throw new Error('Multiple imports on the same line are currently not supported!');
//jk fixed with recursion
 // }

  return matches[2];
}

/** @type {(file: ReadonlyArray<string>, imports: FileData[], options: CompilerOptions) => string[]) }
 * @returns : string[]
*/
function resolveImports(file, imports, options) {
  const { baseUrl, paths } = options;



  /** @type { [key: string]: string[] | undefined } */
  const aliases = {};
  for (const alias in paths) {
    /* istanbul ignore else  */
    if (paths.hasOwnProperty(alias)) {
      let resolved = alias;
      if (alias.endsWith('/*')) {
        resolved = alias.replace('/*', '/');
      }

      aliases[resolved] = paths[alias];
    }
  }

  const lines = [...file];
  for (const imported of imports) {
    const line = file[imported.index];

    let resolved = '';
    for (const alias in aliases) {
      /* istanbul ignore else  */
      if (aliases.hasOwnProperty(alias) && imported.import.startsWith(alias)) {
        const choices = aliases[alias];

        if (choices != undefined) {
          resolved = choices[0];
          if (resolved.endsWith('/*')) {
            resolved = resolved.replace('/*', '/');
          }

          resolved = imported.import.replace(alias, resolved);

          break;
        }
      }
    }

    if (resolved.length < 1) {
      continue;
    }

    let relative = path.relative(path.dirname(imported.path), baseUrl || './');
    relative = path.join(relative, resolved);
    relative = path.relative(path.dirname(imported.path), path.resolve(path.dirname(imported.path), relative));
    relative = relative.replace(/\\/g, '/');

    if (relative.length === 0 || !relative.startsWith('.')) {
      relative = './' + relative;
    }

    lines[imported.index] = line.replace(imported.import, relative);
  }

  return lines;
}


const fs = require('fs')
const sourceDirs = fs.readdirSync('src').filter(f => (f.indexOf(".") < 1))

let createConfig = () => {
  //todo , merge this with fs read tsconfig + user options + maybe like a web_modules
  const config = {
    baseUrl: ".",
    paths: {}
  }
  for (var x of sourceDirs) {
    config.paths[`${x}/*`] = [`src/${x}/*`]
  }
  //return JSON.stringify(config)
  return config
}

const compilerOptions = createConfig()

function compile(filePath, chunk) {
  //const lines = chunk.toString('utf8').split('\n');
  const lines = chunk.split('\n');
  const imports = parseImports(lines, filePath)
  const code = resolveImports(lines, imports, compilerOptions).join('\n')
  return code
}

const unpathifyStream = (file) => {
  if (!/\.tsx?$|\.jsx?$/.test(file) || file.indexOf("node_modules") > 0 || file.indexOf("src") < 0) {
    return new PassThrough();
  }

  var _transform = new Transform()
  _transform._write = (chunk, encoding, next) => {
    _transform.push(compile(file, chunk.toString('utf8')))
    next();
  }
  return _transform
}

module.exports = unpathifyStream
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant