UNPKG

motion

Version:

motion - moving development forward

384 lines (282 loc) 14.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.scripts = scripts; exports.afterBuild = afterBuild; var _helpers = require('./lib/helpers'); var _streams = require('./lib/streams'); var _fns = require('../lib/fns'); var _unicodeToChar = require('../lib/unicodeToChar'); var _unicodeToChar2 = _interopRequireDefault(_unicodeToChar); var _index = require('./index'); var _findRequires = require('../lib/findRequires'); var _babel = require('./babel'); var _babel2 = _interopRequireDefault(_babel); var _bridge = require('../bridge'); var _bridge2 = _interopRequireDefault(_bridge); var _cache = require('../cache'); var _cache2 = _interopRequireDefault(_cache); var _builder = require('../builder'); var _builder2 = _interopRequireDefault(_builder); var _bundler = require('../bundler'); var _bundler2 = _interopRequireDefault(_bundler); var _scanner = require('./scanner'); var _scanner2 = _interopRequireDefault(_scanner); var _opts = require('../opts'); var _opts2 = _interopRequireDefault(_opts); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } const serializeCache = _fns._.debounce(_cache2.default.serialize, 600); const hasFinished = () => hasBuilt() && (0, _opts2.default)('hasRunInitialInstall'); const hasBuilt = () => (0, _opts2.default)('hasRunInitialBuild'); const getAllImports = (src, imports) => [].concat((0, _findRequires.findBabelRuntimeRequires)(src), imports); const scanNow = () => (0, _opts2.default)('build') || (0, _opts2.default)('watch') || !(0, _opts2.default)('hasRunInitialBuild'); function scripts(_ref) { let buildDone = function () { var ref = _asyncToGenerator(function* (file) { if (file.finishingFirstBuild) { _opts2.default.set('hasRunInitialBuild', true); _fns.log.gulp('buildDone!!'.green.bold); waitingForFirstBuild.forEach(function (res) { return res(); }); } }); return function buildDone(_x2) { return ref.apply(this, arguments); }; }(); var _ref$inFiles = _ref.inFiles; let inFiles = _ref$inFiles === undefined ? [] : _ref$inFiles; let userStream = _ref.userStream; let State = { curFile: null, lastError: null, lastSaved: {}, previouslyInstalled: {}, loaded: 0, total: inFiles.length, outsideSources: {} }; const scripts = userStream || _helpers.gulp.src(_helpers.SCRIPTS_GLOB).pipe(_helpers.$.if((0, _opts2.default)('watching'), _helpers.$.watch(_helpers.SCRIPTS_GLOB, { readDelay: 1 }))).pipe(_helpers.$.if(file => file.event == 'unlink', _helpers.$.ignore.exclude(true))); const superStream = new _streams.SuperStream(); return ((0, _opts2.default)('watching') ? _helpers.$.merge(scripts, (0, _streams.dirAddStream)((0, _opts2.default)('appDir')), superStream.getStream()) : scripts).pipe(_helpers.$.if(buildCheck, _helpers.$.ignore.exclude(true))).pipe(_helpers.$.fn(reset)).pipe(_helpers.$.plumber(catchError)).pipe(_helpers.$.fn(setLastFile)).pipe((0, _scanner2.default)('pre')).pipe(_helpers.$.sourcemaps.init()).pipe(_babel2.default.file()).pipe(_helpers.$.fn(processDependencies)).pipe(_helpers.$.fn(sendOutsideChanged)) // right after motion .pipe(_helpers.$.if(!userStream, _helpers.$.rename({ extname: '.js' }))).pipe(_helpers.$.if(file => file.babel.isExported, _helpers.$.multipipe(_helpers.$.fn(removeNewlyInternal), _helpers.$.fn(markFileSuccess), // before writing to preserve path _helpers.gulp.dest((0, _opts2.default)('deps').internalDir), _helpers.$.if(hasBuilt, _helpers.$.fn(_bundler2.default.writeInternals.bind(null, { force: true }))), _helpers.$.fn(buildDone), _helpers.$.ignore.exclude(true)))).pipe(_helpers.$.sourcemaps.write('.')).pipe(_helpers.$.fn(markFileSuccess)).pipe(_helpers.$.if(checkWriteable, _helpers.gulp.dest((0, _opts2.default)('outDir')))).pipe(_helpers.$.fn(afterWrite)) // temporary bugfix because gulp doesnt work well with watch (pending gulp 4) .pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()).pipe(_helpers.$.fn()); function markDone(file) { State.loaded++; const done = State.loaded == State.total; _fns.log.gulp('markDone', State.total, '/', State.loaded, done); // check if done, only run once if (done && !(0, _opts2.default)('hasRunInitialBuild')) { _opts2.default.set('finishingFirstBuild', true); file.finishingFirstBuild = true; } } // only do on first run function buildCheck(file) { file.relativePath = _fns.path.relative((0, _opts2.default)('appDir'), file.path); // BUGFIX gulp sends deleted files through here, this filters them if (!file.contents) return true; // already done with first build if (hasBuilt()) return false; // hide behind cached flag for now if (!(0, _opts2.default)('cached')) { markDone(file); return false; } const prevFile = _cache2.default.getPrevious(file.path); if (!prevFile) return false; let outMTime, srcMTime; // read srcfile try { srcMTime = _fns.fs.statSync(file.path).mtime; } catch (e) { return false; } // read outfile try { const outFile = prevFile.babel.isExported ? _fns.path.join((0, _opts2.default)('deps').dir, 'internal', file.relativePath) : _fns.path.join((0, _opts2.default)('outDir'), file.relativePath); outMTime = _fns.fs.statSync(outFile).mtime; } catch (e) { _fns.log.gulp('buildCheck', 'out file removed'); markDone(file); return false; } // final check const goodBuild = +outMTime > +srcMTime; const goodCache = prevFile.added > srcMTime; if (!goodBuild || !goodCache) return false; return finish(true); function finish() { let restored = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0]; markDone(file); if (restored) { _cache2.default.restorePrevious(file.path); _helpers.out.goodScript(file); afterWrite(file); } return restored; } } function reset(file) { _cache2.default.add(file.path); _fns.emitter.emit('script:start', file); State.lastError = false; State.curFile = file; file.startTime = Date.now(); file.message = { startTime: file.startTime }; } function catchError(error) { _fns.log.gulp('catchError', error); State.lastError = true; _helpers.out.badFile(State.curFile); error.timestamp = Date.now(); error.stack = (0, _unicodeToChar2.default)(error.stack); (0, _fns.logError)(error, State.curFile); _index.event.run('error', State.curFile, error); _cache2.default.addError(error.fileName || '', error); if (error.fileName) error.file = _fns.path.relative((0, _opts2.default)('appDir'), error.fileName); _bridge2.default.broadcast('compile:error', { error }, 'error'); markDone(State.curFile); buildDone(State.curFile); } function setLastFile(file) { if (!(0, _opts2.default)('watching')) return; let name = file.path.replace((0, _opts2.default)('appDir'), ''); if (name.charAt(0) != '/') name = '/' + name; _fns.log.gulp(name); // add to message file.message = _extends({}, file.message, { name: name, path: file.path, compiledAt: file.startTime }); State.curFile = file; } function willInstall(path, imports) { const result = !!_fns._.xor(imports, State.previouslyInstalled[path]).length; State.previouslyInstalled[path] = [].concat(_toConsumableArray(imports)); return result; } // sets isInternal and willInstall // for handling npm and bundling related things function processDependencies(file) { _cache2.default.setFileInternal(file.path, file.babel.isExported); const scan = () => { _cache2.default.setFileImports(file.path, file.babel.imports); _bundler2.default.scanFile(file); }; if ((0, _opts2.default)('watching')) { (0, _fns.debounce)('removeOldImports', 3000, _bundler2.default.uninstall); // check will install file.willInstall = willInstall(file.path, file.babel.imports); if (file.willInstall) superStream.avoidSending(file.path); } // run scan if (file.babel.isExported || scanNow()) scan();else (0, _fns.debounce)(`install:${ file.path }`, 2000, scan); } // detects if a file has changed not inside views for hot reloads correctness function sendOutsideChanged(file) { let src = file.contents.toString(); let meta = _cache2.default.getFileMeta(file.path); if (!meta) return; let changed = true; const viewLocs = Object.keys(meta).map(view => meta[view].location); if (viewLocs.length) { // slice out all code not in views const outerSlice = (ls, start, end) => ls.slice(0, start).concat(ls.slice(end)); const outside = viewLocs.reduce((src, loc) => outerSlice(src, loc[0][0], loc[1][0] + 1), src.split("\n")).join(''); const prevOutside = State.outsideSources[file.path]; changed = prevOutside !== outside; State.outsideSources[file.path] = outside; // update } if ((0, _opts2.default)('hasRunInitialBuild')) _bridge2.default.broadcast('file:outsideChange', { name: _cache2.default.relative(file.path), changed }); } function checkWriteable(file) { if (userStream || State.lastError) return false; if (!(0, _opts2.default)('watching')) return true; const isNew = !State.lastSaved[file.path] || file.startTime > State.lastSaved[file.path]; if (isNew) { State.lastSaved[file.path] = file.startTime; return true; } _fns.log.gulp('not writeable'); return false; } function afterWrite(file) { if ((0, _helpers.isSourceMap)(file.path)) return; buildDone(file); // avoid during initial build if (!hasFinished()) return; if (file.babel.isExported) return; // run stuff after each change on build --watch doBuild(); if (State.lastError) { _fns.log.gulp('State.lastError', State.lastError); return; // avoid if error } const finish = () => { _fns.emitter.emit('script:end', { path: file.relativePath }); _bridge2.default.broadcast('script:add', file.message); }; // dont broadcast script if installing/bundling const isInstalling = _bundler2.default.isInstalling(); if (isInstalling) { _fns.log.gulp('isInstalling', true); return; } if (file.willInstall) { _fns.log.gulp('willInstall', true); _cache2.default.setFileInstalling(file.path, true); return; } finish(); } function doBuild() { if ((0, _opts2.default)('watch') && hasBuilt()) { _builder2.default.build(); return true; } } function markFileSuccess(file) { if ((0, _helpers.isSourceMap)(file.path)) return; _helpers.out.goodScript(file); _fns.log.gulp('DOWN', 'success'.green, 'internal?', file.babel.isExported); if (file.babel.isExported) return; // update cache error / state _cache2.default.update(file.path); // write cache state to disk if ((0, _opts2.default)('hasRunInitialBuild')) serializeCache(); // message browser of compile success _bridge2.default.broadcast('compile:success', file.message, 'error'); // check if other errors left still in queue const error = _cache2.default.getLastError(); if (!error) return; _fns.log.gulp('cache last error', error); _bridge2.default.broadcast('compile:error', { error }, 'error'); } // ok so we start a file // its built into .motion/out // we then add an export // now we need to remove it from .motion/out function removeNewlyInternal(file) { // resolve path from .motion/.internal/deps/internals/xyz.js back to xyz.js // then resolve path to .motion/.internal/out/xyz.js const outPath = (0, _fns.p)((0, _opts2.default)('outDir'), file.relativePath); // log.gulp('remove newly internal', outPath) (0, _fns.rm)(outPath); } } let waitingForFirstBuild = []; function afterBuild() { return new Promise((res, rej) => { if (hasFinished()) return res();else waitingForFirstBuild.push(res); }); } //# sourceMappingURL=scripts.js.map