Skip to content

Commit

Permalink
feat(cli): dynamic inject directive runtime dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
Genuifx committed Mar 13, 2020
1 parent c2a1f4b commit 160008e
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 58 deletions.
67 changes: 35 additions & 32 deletions packages/wxa-cli/src/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import DependencyResolver from './helpers/dependencyResolver';
import root from './const/root';
import ProgressTextBar from './helpers/progressTextBar';
import color from './const/color';
import {DirectiveBroker} from './directive/directiveBroker';

let debug = debugPKG('WXA:Builder');
class Builder {
Expand Down Expand Up @@ -91,9 +92,9 @@ class Builder {
this.isWatching = true;

// set mode
this.schedule.set('mode', 'watch');
this.scheduler.set('mode', 'watch');

let files = this.filterModule(this.schedule.$indexOfModule);
let files = this.filterModule(this.scheduler.$indexOfModule);

if (cmd.verbose) {
logger.info('File to Watch ', files.length);
Expand All @@ -111,26 +112,26 @@ class Builder {

logger.warn('change', filepath);
debug('WATCH file changed %s', filepath);
let mdl = this.schedule.$indexOfModule.get(filepath);
let mdl = this.scheduler.$indexOfModule.get(filepath);

if (mdl == null) {
// maybe outer dependencies.
let defer = [];

this.schedule.$indexOfModule.forEach((mdl)=>{
this.scheduler.$indexOfModule.forEach((mdl)=>{
if (!mdl.outerDependencies || !mdl.outerDependencies.size || !mdl.outerDependencies.has(filepath)) return;

defer.push(async ()=>{
try {
this.schedule.$depPending.push(mdl);
this.scheduler.$depPending.push(mdl);
// 2019-08-20 childNodes will auto mark in scheduler
// if (mdl.childNodes && mdl.childNodes.size) this.walkChildNodesTreeAndMark(mdl);

await this.hooks.rebuildModule.promise(this.schedule, mdl);
await this.hooks.rebuildModule.promise(this.scheduler, mdl);

let changedDeps = await this.schedule.$doDPA();
let changedDeps = await this.scheduler.$doDPA();
let map = new Map(changedDeps.map((mdl)=>[mdl.src, mdl]));
await this.optimizeAndGenerate(map, this.schedule.appConfigs, cmd);
await this.optimizeAndGenerate(map, this.scheduler.appConfigs, cmd);
} catch (e) {
error('编译失败', {error: e});
}
Expand Down Expand Up @@ -190,20 +191,20 @@ class Builder {

let changedDeps;
try {
this.schedule.$depPending.push(mdl);
this.scheduler.$depPending.push(mdl);
// 2019-08-20 childNodes will auto mark in scheduler
// if (mdl.childNodes && mdl.childNodes.size) this.walkChildNodesTreeAndMark(mdl);

await this.hooks.rebuildModule.promise(this.schedule, mdl);
await this.hooks.rebuildModule.promise(this.scheduler, mdl);

changedDeps = await this.schedule.$doDPA();
changedDeps = await this.scheduler.$doDPA();
let map = new Map(changedDeps.map((mdl)=>[mdl.src, mdl]));
await this.optimizeAndGenerate(map, this.schedule.appConfigs, cmd);
await this.optimizeAndGenerate(map, this.scheduler.appConfigs, cmd);
} catch (e) {
// error('编译失败', {error: e});
}

let newFiles = this.filterModule(this.schedule.$indexOfModule);
let newFiles = this.filterModule(this.scheduler.$indexOfModule);
let unlinkFiles = files.filter((oldFilePath)=>!~newFiles.indexOf(oldFilePath));
let addFiles = newFiles.filter((filePath)=>!~files.indexOf(filePath));

Expand All @@ -217,7 +218,7 @@ class Builder {
if (addFiles && addFiles.length) this.watcher.add(addFiles);
if (unlinkFiles && unlinkFiles.length) this.watcher.unwatch(unlinkFiles);

await this.hooks.finishRebuildModule.promise(this.schedule, mdl);
await this.hooks.finishRebuildModule.promise(this.scheduler, mdl);

return {isChange, newFiles};
} else {
Expand All @@ -236,14 +237,15 @@ class Builder {
}
await this.hooks.beforeRun.promise(this);

this.schedule = new Schedule(this.loader);
applyPlugins(this.wxaConfigs.plugins || [], this.schedule);
this.schedule.progress.toggle(cmd.progress);
this.schedule.set('cmdOptions', cmd);
this.schedule.set('wxaConfigs', this.wxaConfigs || {});
this.scheduler = new Schedule(this.loader);
this.directiveBroker = new DirectiveBroker(this.scheduler);

applyPlugins(this.wxaConfigs.plugins || [], this.scheduler);
this.scheduler.progress.toggle(cmd.progress);
this.scheduler.set('cmdOptions', cmd);
this.scheduler.set('wxaConfigs', this.wxaConfigs || {});
this.scheduler.set('directiveBroker', this.directiveBroker);

debug('builder wxaConfigs is %O', this.wxaConfigs);
debug('schedule options is %O', this.schedule);
try {
await this.handleEntry(cmd);
} catch (error) {
Expand All @@ -262,18 +264,19 @@ class Builder {
await this.hooks.run.promise(this);

// do dependencies analysis.
await this.schedule.doDPA();
await this.scheduler.doDPA();
await this.directiveBroker.run();

this.schedule.perf.show();
this.scheduler.perf.show();

try {
debug('schedule dependencies Tree is %O', this.schedule.$indexOfModule);
await this.optimizeAndGenerate(this.schedule.$indexOfModule, this.schedule.appConfigs, cmd);
debug('schedule dependencies Tree is %O', this.scheduler.$indexOfModule);
await this.optimizeAndGenerate(this.scheduler.$indexOfModule, this.scheduler.appConfigs, cmd);

// done.
await this.hooks.done.promise(this.schedule);
await this.hooks.done.promise(this.scheduler);

debug('Project Pages', this.schedule.$pageArray);
debug('Project Pages', this.scheduler.$pageArray);

logger.log('Done', 'AT: '+new Date().toLocaleString());
} catch (e) {
Expand All @@ -298,12 +301,12 @@ class Builder {
cmdOptions: cmdOptions,
appConfigs: appConfigs,
});
applyPlugins(this.schedule.wxaConfigs.plugins, optimizer);
applyPlugins(this.scheduler.wxaConfigs.plugins, optimizer);

await optimizer.run(indexedMap);

// write module to dest, dependencies copy.
let generator = new Generator(this.current, this.schedule.meta, this.wxaConfigs, cmdOptions);
let generator = new Generator(this.current, this.scheduler.meta, this.wxaConfigs, cmdOptions);
let generateTasks = [];
indexedMap.forEach((mdl)=>{
generateTasks.push(generator.do(mdl));
Expand All @@ -320,7 +323,7 @@ class Builder {
}

async handleEntry(cmd) {
let entry = this.schedule.wxaConfigs.entry || [];
let entry = this.scheduler.wxaConfigs.entry || [];
if (!Array.isArray(entry)) throw new Error('Entry Point is not array!');

let isAPP = (filepath)=>/app\./.test(filepath);
Expand Down Expand Up @@ -355,7 +358,7 @@ class Builder {
}
}

let dr = new DependencyResolver(this.schedule.wxaConfigs.resolve, this.schedule.meta);
let dr = new DependencyResolver(this.scheduler.wxaConfigs.resolve, this.scheduler.meta);
let outputPath = dr.getOutputPath(point, defaultPret, root);

mdl = {
Expand All @@ -370,7 +373,7 @@ class Builder {
};

if (isFile(mdl.src)) {
this.schedule.addEntryPoint(mdl);
this.scheduler.addEntryPoint(mdl);
} else {
throw new Error(`入口文件不存在 ${mdl.src}`);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/wxa-cli/src/compilers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export default class Compiler {
}

$$parseXML(mdl) {
let deps = new XMLManager(this.resolve || {}, this.meta, this.$scheduer.wxaConfigs, this.$scheduer.cmdOptions).parse(mdl);
let deps = new XMLManager(this.resolve || {}, this.meta, this.$scheduer).parse(mdl);

debug('xml dependencies %o', deps);
// analysis deps;
Expand Down
61 changes: 61 additions & 0 deletions packages/wxa-cli/src/directive/directiveBroker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Events from 'events';
import path from 'path';
import color from '../const/color';

let runtimeDirectiveInjectMap = new Map([
[
'mock', async function(scheduler) {
scheduler.$indexOfModule.forEach((mdl)=>{
if (
mdl.category &&
mdl.category.toLowerCase() === 'app' &&
path.extname(mdl.src) === '.js' &&
!/wxa:\/\/wxa\/directive/g.test(mdl.code)
) {
mdl.color = color.CHANGED;
mdl.content = `require('wxa://wxa/directive/index.js'); ${mdl.content}`;

scheduler.$depPending.push(mdl);
}
});

await scheduler.$doDPA();
},
],
]);

class DirectiveBroker extends Events {
constructor(scheduler) {
super();
this.$scheduler = scheduler;
this.$directiveSet = new Set();

// 监听事件
this.on('add', (name) => {
this.$directiveSet.add(name);
});

this.on('remove', (name) => {
this.$directiveSet.delete(name);
});
}

destory() {
this.$directiveSet.clear();
this.$scheduler = null;
}

async run() {
let tasks = [];
this.$directiveSet.forEach((directiveName) => {
let process = runtimeDirectiveInjectMap.get(directiveName);

if (process) tasks.push(process.call(null, this.$scheduler));
});

await Promise.all(tasks);
}
}

export {DirectiveBroker};

Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export default directive;

const directiveHandlerList = {
mock,
// anotherDirective
// ...
};

function directive(drc, element, options) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
指令格式1:`wxa:mock="占位符"` 或 `wxa:mock="占位符(参数[,参数])"`
*/

import {addClass} from '../../../utils';
import {addClass} from '../../utils';
export default mock;

// ============================================================
Expand All @@ -27,13 +27,15 @@ let idCount = 1;


// >>>> Main -----------------------------
function mock(drc, element, options) {
console.log(options.cmdOptions);
function mock(drc, element, app) {
console.log(app.cmdOptions);
if (
options.cmdOptions.mock &&
app.cmdOptions.mock &&
// 非生产环境
['prod', 'production'].indexOf(process.env.NODE_ENV) === -1
) {
app.addDirective('mock');

// 找到需要执行指令命令的节点
let targetList = findMockTarget(element);
targetList.forEach((target) => {
Expand Down
22 changes: 17 additions & 5 deletions packages/wxa-cli/src/resolvers/xml/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DependencyResolver from '../../helpers/dependencyResolver';
import CSSManager from '../styleResolver';
import debugPKG from 'debug';
import {logger, error} from '../../helpers/logger';
import directive from '../directive';
import directive from '../../directive/index';
import {serializeXML} from '../../compilers/xml';

let debugXMLStyle = debugPKG('WXA:XMLManager-style');
Expand All @@ -13,12 +13,13 @@ const WXA_DIRECTIVE_PREFIX = 'wxa';
const WECHAT_DIRECTIVE_PREFIX = 'wx';

class XMLManager {
constructor(resolve, meta, wxaConfigs, cmdOptions) {
constructor(resolve, meta, scheduler) {
this.$scheduler = scheduler;
this.resolve = resolve;
this.meta = meta;

this.wxaConfigs = wxaConfigs;
this.cmdOptions = cmdOptions;
this.wxaConfigs = scheduler.wxaConfigs;
this.cmdOptions = scheduler.cmdOptions;
}

parse(mdl) {
Expand Down Expand Up @@ -152,7 +153,18 @@ class XMLManager {
name: attr.name,
value: attr.value,
};
directive(drc, element, {mdl, cmdOptions: this.cmdOptions, wxaConfigs: this.wxaConfigs});
directive(drc, element, {
mdl,
cmdOptions: this.cmdOptions,
wxaConfigs: this.wxaConfigs,
addDirective: (name) => {
debugger;
this.$scheduler.directiveBroker.emit('add', name);
},
removeDirective: (name) => {
this.$scheduler.directiveBroker.emit('remove', name);
},
});
}
// 微信小程序指令
case WECHAT_DIRECTIVE_PREFIX: {
Expand Down
12 changes: 0 additions & 12 deletions packages/wxa-cli/src/schedule.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ class Schedule {
this.perf.markEnd(relativeSrc);

// try to wrap wxa every app and page
this.tryWrapDirective(dep);
this.tryWrapWXA(dep);
this.tryAddPolyfill(dep);

Expand Down Expand Up @@ -364,17 +363,6 @@ class Schedule {
}
}

tryWrapDirective(mdl) {
if (
mdl.category &&
mdl.category.toLowerCase() === 'app' &&
path.extname(mdl.src) === '.js' &&
!/wxa:\/\/wxa\/directive/g.test(mdl.code)
) {
mdl.code = `require('wxa://wxa/directive/index.js'); ${mdl.code}`;
}
}

tryAddPolyfill(mdl) {
if (!this.wxaConfigs.polyfill) return;

Expand Down
4 changes: 2 additions & 2 deletions packages/wxa-cli/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export function promiseSerial(funs) {

export function getClassSet(classStr) {
let classList = [];
if(classStr && typeof classStr === 'string') {
if (classStr && typeof classStr === 'string') {
classList = classStr.split(' ');
}
return new Set(classList);
Expand All @@ -172,4 +172,4 @@ export function removeClass(classStr, destClass) {
let classSet = getClassSet(classStr);
classSet.delete(destClass);
return Array.from(classSet);
}
}

0 comments on commit 160008e

Please sign in to comment.