okam-build
Version:
The build tool for Okam develop framework
193 lines (165 loc) • 5.21 kB
JavaScript
/**
* @file load the files to be processed
* @author sparklewhy@gmail.com
*/
;
const path = require('path');
const fs = require('fs');
const glob = require('glob');
const MM = require('minimatch').Minimatch;
const {getFileState, relative} = require('../util').file;
const FileFactory = require('../processor/FileFactory');
function traverseFiles(rootDir, filter) {
let toProcessDirs = [rootDir];
while (toProcessDirs.length) {
let currDir = toProcessDirs.pop();
let files = fs.readdirSync(currDir);
for (let i = 0, len = files.length; i < len; i++) {
let fileName = files[i];
if (/^\./.test(fileName)) {
continue;
}
let fullPath = path.resolve(currDir, fileName);
let relativePath = relative(fullPath, rootDir);
let stat = getFileState(fullPath);
if (!stat) {
continue;
}
let isDir = stat.isDirectory();
if (filter(relativePath, isDir, fullPath)) {
continue;
}
if (isDir) {
toProcessDirs.push(fullPath);
}
}
}
}
function addFileRule(allRules, rule) {
if (typeof rule === 'string') {
let m = new MM(rule, {matchBase: true});
allRules.push(m);
}
else if (rule instanceof RegExp) {
allRules.push({match: str => rule.test(str)});
}
}
function resolvePath(file, rootDir) {
if (typeof file === 'string') {
return relative(path.resolve(rootDir, file), rootDir);
}
return file;
}
function filterFiles(ctx, file, isDir, fullPath) {
let {
sourceDir,
sourcePathPrefix,
excludeRules,
customIncludeRules,
fileFactory,
initBuildFiles
} = ctx;
if (isDir && file === sourceDir) {
return false;
}
let isFilter = excludeRules && excludeRules.some(item => item.match(file));
if (isFilter) {
return true;
}
let isCustomInclude = customIncludeRules.some(item => item.match(file));
if (!isCustomInclude && file.indexOf(sourcePathPrefix) !== 0) {
return true;
}
if (isDir) {
return false;
}
let toProcessFile = fileFactory.createFile({
path: file,
fullPath
});
// ensure the entry app script can be compiled at first
if (toProcessFile.isEntryScript
|| toProcessFile.isEntryStyle
|| toProcessFile.isProjectConfig
) {
initBuildFiles.unshift(toProcessFile);
}
else if (toProcessFile.isImg || isCustomInclude) {
// by default all image files will be processed and output as for
// we cannot analysis the used image resources correctly
// add custom included files as default init process files
initBuildFiles.push(toProcessFile);
}
fileFactory.push(toProcessFile);
}
function addExtraIncludeFiles(includeGlob, initBuildFiles, fileFactory) {
if (!Array.isArray(includeGlob)) {
return;
}
let {root} = fileFactory;
includeGlob.forEach(pattern => {
glob.sync(pattern, {
cwd: root
}).forEach(item => {
item = path.join(root, item);
let file = fileFactory.addFile(item);
if (!initBuildFiles.includes(file)) {
initBuildFiles.push(file);
}
});
});
}
function loadProcessFiles(options, logger) {
let rootDir = options.root;
let {dir, exclude, include} = options.source;
if (!dir) {
logger.error('missing the source dir config information');
return;
}
const initBuildFiles = [];
let componentExtname = options.component.extname;
let {style: entryStyle, script: entryScript, projectConfig} = options.entry;
entryStyle = resolvePath(entryStyle, rootDir);
entryScript = resolvePath(entryScript, rootDir);
projectConfig = resolvePath(projectConfig, rootDir);
let sourceDir = resolvePath(dir, rootDir);
let excludeRules = [];
exclude && exclude.forEach(addFileRule.bind(this, excludeRules));
excludeRules.length || (excludeRules = null);
let customIncludeRules = [];
let includeGlob = [];
include && include.forEach(item => {
if (typeof item === 'string') {
includeGlob.push(item);
}
else {
addFileRule(customIncludeRules, item);
}
});
let fileFactory = new FileFactory({
root: rootDir,
rebaseDepDir: (options.output || {}).depDir,
entryStyle,
entryScript,
projectConfig,
componentExtname
});
let onFilter = filterFiles.bind(null, {
sourceDir,
sourcePathPrefix: `${sourceDir}/`,
excludeRules,
customIncludeRules,
fileFactory,
initBuildFiles
});
logger.debug('load files', rootDir, sourceDir);
traverseFiles(rootDir, onFilter);
addExtraIncludeFiles(includeGlob, initBuildFiles, fileFactory);
return {
root: rootDir,
sourceDir,
files: fileFactory,
buildFiles: initBuildFiles
};
}
module.exports = loadProcessFiles;