diff --git a/packages/wepy-cli/src/compile-script.js b/packages/wepy-cli/src/compile-script.js index 771427c19..a21554335 100644 --- a/packages/wepy-cli/src/compile-script.js +++ b/packages/wepy-cli/src/compile-script.js @@ -24,31 +24,44 @@ let appPath, npmPath, src, dist; export default { resolveDeps (code, type, opath) { - let params = cache.getParams(); let config = cache.getConfig(); let wpyExt = params.wpyExt; - let npmInfo = opath.npm; return code.replace(/require\(['"]([\w\d_\-\.\/@]+)['"]\)/ig, (match, lib) => { + let npmInfo = opath.npm; + if (lib === './_wepylogs.js') { return match; } let resolved = lib; - let target = '', source = '', ext = '', needCopy = false; if (config.output === 'ant' && lib === 'wepy') { lib = 'wepy-ant'; } - lib = resolve.resolveAlias(lib); - if (path.isAbsolute(lib)) { + lib = resolve.resolveAlias(lib, opath); + if (lib === 'false') { + return `{}` + } else if (path.isAbsolute(lib)) { source = lib; target = util.getDistPath(source); } else if (lib[0] === '.') { // require('./something''); - source = path.join(opath.dir, lib); // e:/src/util + let resolvedLib; + if (npmInfo && npmInfo.pkg._activeFields.length) { + resolvedLib = resolve.resolveSelfFields(npmInfo.dir, npmInfo.pkg, path.join(path.relative(npmInfo.dir, opath.dir), lib)); + } + if (resolvedLib) { + source = path.join(npmInfo.dir, resolvedLib); + lib = path.relative(opath.dir, source); + if (lib[0] !== '.') { + lib = './' + lib; + } + } else { + source = path.join(opath.dir, lib); + } if (type === 'npm') { target = path.join(npmPath, path.relative(npmInfo.modulePath, source)); needCopy = true; @@ -61,6 +74,11 @@ export default { lib.indexOf('/') === lib.length - 1 || // reqiore('a/b/something/') (lib[0] === '@' && lib.indexOf('/') !== -1 && lib.lastIndexOf('/') === lib.indexOf('/')) // require('@abc/something') ) { + // require('stream') -> browsers: emitter->emitter-component; + if (npmInfo && npmInfo.pkg._activeFields.length) { + let resolvedLib = resolve.resolveSelfFields(npmInfo.dir, npmInfo.pkg, lib); + lib = resolvedLib ? resolvedLib : lib; + } let mainFile = resolve.getMainFile(lib); @@ -71,12 +89,19 @@ export default { lib: lib, dir: mainFile.dir, modulePath: mainFile.modulePath, - file: mainFile.file + file: mainFile.file, + pkg: mainFile.pkg }; - source = path.join(mainFile.dir, mainFile.file); - target = path.join(npmPath, lib, mainFile.file); - lib += path.sep + mainFile.file; + let resolvedFile; + if (mainFile.pkg && mainFile.pkg._activeFields.length) { + resolvedFile = resolve.resolveSelfFields(mainFile.dir, mainFile.pkg, mainFile.file); + } + resolvedFile = resolvedFile ? resolvedFile : mainFile.file; + source = path.join(mainFile.dir, resolvedFile); + target = path.join(npmPath, lib, resolvedFile); + + lib += path.sep + resolvedFile; ext = ''; needCopy = true; } else { // require('babel-runtime/regenerator') diff --git a/packages/wepy-cli/src/compile-style.js b/packages/wepy-cli/src/compile-style.js index 03022b52e..15a028e91 100644 --- a/packages/wepy-cli/src/compile-style.js +++ b/packages/wepy-cli/src/compile-style.js @@ -106,12 +106,14 @@ export default { requires.forEach((r) => { let comsrc = null; isNPM = false; - if (path.isAbsolute(r)) { - if (path.extname(r) === '' && util.isFile(r + ext)) { - comsrc = r + ext; + let lib = resolve.resolveAlias(r, opath); + + if (path.isAbsolute(lib)) { + if (path.extname(lib) === '' && util.isFile(lib + ext)) { + comsrc = lib + ext; } } else { - let lib = resolve.resolveAlias(r); + // let lib = resolve.resolveAlias(r, opath); if (path.isAbsolute(lib)) { comsrc = lib; } else { diff --git a/packages/wepy-cli/src/compile-wpy.js b/packages/wepy-cli/src/compile-wpy.js index cd9d5e6c4..f63ac0b05 100644 --- a/packages/wepy-cli/src/compile-wpy.js +++ b/packages/wepy-cli/src/compile-wpy.js @@ -373,7 +373,7 @@ export default { } }); if (Object.keys(props).length) { - rst.script.code =rst.script.code.replace(/[\s\r\n]components\s*=[\s\r\n]*/, (match, item, index) => { + rst.script.code = rst.script.code.replace(/[\s\r\n]components\s*=[\s\r\n]*/, (match, item, index) => { return `$repeat = ${JSON.stringify($repeat)};\r\n$props = ${JSON.stringify(props)};\r\n$events = ${JSON.stringify(events)};\r\n${match}`; }); } @@ -471,6 +471,14 @@ export default { } else { requires.push(path.join(opath.dir, wpy.template.components[k])); } + + // 去重 + // Example: + // components = { + // Count1: '../components/count', + // Count2: '../components/count' + // }; + requires = util.unique(requires) } } try { diff --git a/packages/wepy-cli/src/compile.js b/packages/wepy-cli/src/compile.js index ba1e52654..7ecf15d3a 100644 --- a/packages/wepy-cli/src/compile.js +++ b/packages/wepy-cli/src/compile.js @@ -50,7 +50,7 @@ export default { reg = new RegExp('\\' + ext + '$'); if (!reg.test(importpath)) importpath = importpath + ext; - let resolved = resolve.resolveAlias(importpath); + let resolved = resolve.resolveAlias(importpath, opath); let compath; if (path.isAbsolute(resolved)) { compath = path.resolve(resolved); @@ -166,6 +166,7 @@ export default { util.error('没有检测到wepy.config.js文件, 请执行`wepy new demo`创建'); return false; } + resolve.init(wepyrc.resolve || {}); loader.attach(resolve); @@ -202,11 +203,17 @@ export default { if (config.output === 'web') { - wepyrc.web = wepyrc.web || {}; - wepyrc.web.dist = wepyrc.web.dist || 'web'; - wepyrc.web.src = wepyrc.web.src || 'src'; + wepyrc.build = wepyrc.build || {}; + wepyrc.build.web = wepyrc.build.web || {}; + wepyrc.build.web.dist = wepyrc.build.web.dist || 'web'; + wepyrc.build.web.src = wepyrc.build.web.src || 'src'; + if (wepyrc.build.web.resolve) + wepyrc.resolve = Object.assign({}, wepyrc.resolve, wepyrc.build.web.resolve); wepyrc.output = 'web'; + resolve.init(wepyrc.resolve || {}); + loader.attach(resolve); + if (!resolve.getPkg('wepy-web')) { util.log('正在尝试安装缺失资源 wepy-web,请稍等。', '信息'); util.exec(`npm install wepy-web --save`).then(d => { @@ -219,11 +226,17 @@ export default { return false; } } else if (config.output === 'ant') { - wepyrc.ant = wepyrc.ant || {}; - wepyrc.ant.dist = wepyrc.ant.dist || 'ant'; - wepyrc.ant.src = wepyrc.ant.src || 'src'; + wepyrc.build = wepyrc.build || {}; + wepyrc.build.ant = wepyrc.build.ant || {}; + wepyrc.build.ant.dist = wepyrc.build.ant.dist || 'ant'; + wepyrc.build.ant.src = wepyrc.build.ant.src || 'src'; + if (wepyrc.build.ant.resolve) + wepyrc.resolve = Object.assign({}, wepyrc.resolve, wepyrc.build.ant.resolve); wepyrc.output = 'ant'; + resolve.init(wepyrc.resolve || {}); + loader.attach(resolve); + if (!resolve.getPkg('wepy-ant')) { util.log('正在尝试安装缺失资源 wepy-ant,请稍等。', '信息'); util.exec(`npm install wepy-ant --save`).then(d => { @@ -236,6 +249,7 @@ export default { return false; } } + return true; }, @@ -393,4 +407,4 @@ export default { }); } } -} \ No newline at end of file +} diff --git a/packages/wepy-cli/src/resolve.js b/packages/wepy-cli/src/resolve.js index a9473799b..fd4d930f6 100644 --- a/packages/wepy-cli/src/resolve.js +++ b/packages/wepy-cli/src/resolve.js @@ -10,17 +10,65 @@ import path from 'path'; import util from './util'; +import cache from './cache' + +const DEFAULT_MODULES = ['node_modules']; +const DEFAULT_ALIASFIELDS = ['wepy', 'weapp', 'browser']; +const DEFAULT_MAINFIELDS = ['wepy', 'weapp', 'browser', 'module', 'main']; export default { init (config) { - this.modules = config.modules || ['node_modules']; this.alias = config.alias; + this.modules = config.modules || DEFAULT_MODULES; + this.aliasFields = config.aliasFields || DEFAULT_ALIASFIELDS; + this.mainFields = config.mainFields || DEFAULT_MAINFIELDS; - if (typeof this.modules === 'string') { - this.modules = [this.modules]; - } - - let cwd = process.cwd(); + ['modules', 'aliasFields', 'mainFields'].forEach(opt => { + typeof this[opt] === 'string' && ( + this[opt] = [].concat(this[opt]) + ); + }); + + let pkgFile = util.getPkg(); + let pkg = JSON.parse(pkgFile); + let cwd = util.currentDir; + let ext = cache.getExt(); + + // 优先级递减 + this.aliasFields.forEach(fields => { + // 归类 + util.isObject(pkg[fields]) && Object.keys(pkg[fields] || {}).forEach(key => { + // module形式的fieldsAlias归置于alias中,例: "xyz": "./src/xyz.js",alias优先级较大 + if (key.indexOf('.') === -1) { + // => "xyz"、"xyz-xyz" + let value; + if (!pkg[fields][key]) { + value = 'false'; + } else { + value = path.resolve(cwd, pkg[fields][key]); + } + + // fields中key或value路径后缀与配置缺省值相同时,replace后缀 + if (path.extname(value) === ext) + value = value.replace(ext, ''); + + this.alias = Object.assign({}, { [key]: value }, this.alias || {}); + } else if (!path.isAbsolute(key)) { + // relative path + let value = path.resolve(cwd, pkg[fields][key]); + key = path.resolve(cwd, key); + + // fields中key或value路径后缀与配置缺省值相同时,replace后缀 + if (path.extname(key) === ext) + key = key.replace(ext, ''); + + if (path.extname(value) === ext) + value = value.replace(ext, ''); + + this.fieldsAlias = Object.assign({}, { [key]: value }, this.fieldsAlias || {}); + } + }); + }); this.modulePaths = this.modules.map(v => { if (path.isAbsolute(v)) { @@ -83,6 +131,14 @@ export default { } if (!pkg) return null; + + // make sure fields is used in this package. + pkg._activeFields = []; + this.aliasFields.forEach(field => { + if (pkg[field]) { + pkg._activeFields.push(field); + } + }); return { pkg: pkg, modulePath: o.modulePath, @@ -95,10 +151,19 @@ export default { if (!o) { return null; } - let main = o.pkg.main || 'index.js'; - if (o.pkg.browser && typeof o.pkg.browser === 'string') { - main = o.pkg.browser; + + // 优先级递减 + let mainField, main + for (let i = 0, l = this.mainFields.length; i < l; i++) { + mainField = this.mainFields[i]; + if (o.pkg[mainField] && typeof o.pkg[mainField] === 'string') { + main = o.pkg[mainField]; + break; + } } + + main = main || 'index.js'; + return { file: main, modulePath: o.modulePath, @@ -107,13 +172,72 @@ export default { }; }, - resolveAlias (lib) { + /* + resolve package with contains different fields + */ + resolveSelfFields (dir, pkg, lib) { + for (let i = 0, l = pkg._activeFields.length; i < l; i++) { + let field = pkg[pkg._activeFields[i]]; + if (field) { + for (let k in field) { + // in Window, path may be dist\a\b, but in package.json it is ./dist/a/b, so can not just simply use === + let matchPath = path.join(dir, k); + let requirePath = path.join(dir, lib); + if (matchPath === requirePath || matchPath === requirePath + path.extname(matchPath)) { + return field[k]; + } + } + } + } + return null; + }, + + resolveFieldsAlias (lib) { + return lib && this.fieldsAlias && this.fieldsAlias[lib] + ? this.fieldsAlias[lib] + : lib; + }, + + replaceFieldsAlias (currentAlias, opath) { + let absolutePath; + + if (path.isAbsolute(currentAlias)) { + absolutePath = currentAlias; + + currentAlias = this.resolveFieldsAlias(absolutePath) !== absolutePath + ? this.resolveFieldsAlias(absolutePath) + : currentAlias; + } else if (currentAlias[0] === '.') { + absolutePath = path.join(opath.dir, currentAlias); + + currentAlias = this.resolveFieldsAlias(absolutePath) !== absolutePath + ? this.resolveFieldsAlias(absolutePath) + : currentAlias; + } else if ( + currentAlias.indexOf('/') === -1 || // require('asset'); + currentAlias.indexOf('/') === currentAlias.length - 1 || // require('a/b/something/') + (currentAlias[0] === '@' && currentAlias.indexOf('/') !== -1 && currentAlias.lastIndexOf('/') === currentAlias.indexOf('/')) // require('@abc/something') + ) { + const mainFile = this.getMainFile(currentAlias); + + if (mainFile) { + absolutePath = path.join(mainFile.dir, mainFile.file); + currentAlias = this.resolveFieldsAlias(absolutePath) !== absolutePath + ? this.resolveFieldsAlias(absolutePath) + : currentAlias; + } + } + return currentAlias; + }, + + resolveAlias (lib, opath) { if (!this.alias) return lib; if (this._cacheAlias[lib]) { return this._cacheAlias[lib]; } let rst = lib; + let ext = cache.getExt(); for (let k in this.alias) { let alias = this.alias[k]; @@ -128,13 +252,18 @@ export default { } } else { if ((lib.indexOf(k) === 0 && lib === k) || (lib !== k && lib.indexOf(k + '/') === 0)) { - this._cacheAlias[lib] = path.resolve(lib.replace(k, alias)); + this._cacheAlias[lib] = lib.replace(k, alias); + if (this._cacheAlias[lib] !== 'false') { + this._cacheAlias[lib] = path.resolve(this._cacheAlias[lib]); + } } } } if (!this._cacheAlias[lib]) { this._cacheAlias[lib] = lib; } + // replace field alias + this._cacheAlias[lib] = this.replaceFieldsAlias(this._cacheAlias[lib], opath); return this._cacheAlias[lib]; } -} \ No newline at end of file +} diff --git a/packages/wepy-cli/src/util.js b/packages/wepy-cli/src/util.js index f89420827..e764c572c 100644 --- a/packages/wepy-cli/src/util.js +++ b/packages/wepy-cli/src/util.js @@ -478,6 +478,10 @@ const utils = { let ignoreFile = path.join(this.currentDir, path.sep, '.wepyignore'); return this.isFile(ignoreFile) ? this.readFile(ignoreFile) : ''; }, + getPkg () { + let pkgFile = path.join(this.currentDir, path.sep, 'package.json'); + return this.isFile(pkgFile) ? this.readFile(pkgFile) : '{}'; + }, getFiles (dir = process.cwd(), prefix = '') { let cfiles = cache.getFileList(dir); if (cfiles) diff --git a/packages/wepy-cli/src/web/compile-script.js b/packages/wepy-cli/src/web/compile-script.js index a4992cd69..4d7b6b07a 100644 --- a/packages/wepy-cli/src/web/compile-script.js +++ b/packages/wepy-cli/src/web/compile-script.js @@ -40,6 +40,7 @@ export default { let wpyExt = params.wpyExt; let depences = []; + // wpy.script.code = wpy.script.code.replace(/require\(['"]([\w\d_\-\.\/]+)['"]\)/ig, (match, lib) => { wpy.script.code = wpy.script.code.replace(/require\(['"]([\w\d_\-\.\/@]+)['"]\)/ig, (match, lib) => { if (lib === 'wepy') @@ -51,14 +52,35 @@ export default { let dep = {}, npmInfo; - lib = resolve.resolveAlias(lib); + lib = resolve.resolveAlias(lib, opath); - if (path.isAbsolute(lib)) { + if (lib === 'false') { + return '{}'; + } else if (path.isAbsolute(lib)) { source = lib; } else if (lib[0] === '.') { // require('./something''); - source = path.join(opath.dir, lib); // e:/src/util + let resolvedLib; + if (wpy.npm && wpy.npm.pkg._activeFields.length) { + resolvedLib = resolve.resolveSelfFields(wpy.npm.dir, wpy.npm.pkg, path.join(path.relative(wpy.npm.dir, opath.dir), lib)); + } + if (resolvedLib) { + source = path.join(wpy.npm.dir, resolvedLib); + lib = path.relative(opath.dir, source); + if (lib[0] !== '.') { + lib = './' + lib; + } + } else { + source = path.join(opath.dir, lib); + } + npmInfo = wpy.npm; // relative path in npm package } else if (lib.indexOf('/') === -1 || lib.indexOf('/') === lib.length - 1) { // require('asset'); + // require('stream') -> browsers: emitter->emitter-component; + if (wpy.npm && wpy.npm.pkg._activeFields.length) { + let resolvedLib = resolve.resolveSelfFields(wpy.npm.dir, wpy.npm.pkg, lib); + lib = resolvedLib ? resolvedLib : lib; + } + let o = resolve.getMainFile(lib); if (!o) { let relative = path.relative(util.currentDir, wpy.script.src); @@ -66,16 +88,24 @@ export default { } let pkg = o.pkg; let main = pkg.main || 'index.js'; + + let resolvedFile; + if (o.pkg && o.pkg._activeFields.length) { + resolvedFile = resolve.resolveSelfFields(o.dir, o.pkg, o.file); + } + resolvedFile = resolvedFile ? resolvedFile : o.file; + + if (lib === 'axios') { - main = path.join('dist', 'axios.js'); + resolvedFile = path.join('dist', 'axios.js'); } else if (lib === 'vue') { - main = path.join('dist', 'vue.js'); + resolvedFile = path.join('dist', 'vue.js'); } if (pkg.browser && typeof pkg.browser === 'string') { - main = pkg.browser; + resolvedFile = pkg.browser; } - source = path.join(o.dir, main); - lib += path.sep + main; + source = path.join(o.dir, resolvedFile); + lib += path.sep + resolvedFile; npmInfo = o; } else { // require('babel-runtime/regenerator') //console.log('3: ' + lib); @@ -95,6 +125,8 @@ export default { source += wpyExt; } else if (util.isFile(source + '.js')) { source += '.js'; + } else if (util.isDir(source) && util.isFile(source + path.sep + 'index.js')) { + source += path.sep + 'index.js'; } else { source = null; } diff --git a/packages/wepy-cli/templates/template/package.json b/packages/wepy-cli/templates/template/package.json index db59540a7..af4d83220 100644 --- a/packages/wepy-cli/templates/template/package.json +++ b/packages/wepy-cli/templates/template/package.json @@ -8,6 +8,10 @@ "build": "cross-env NODE_ENV=production wepy build --no-cache", "test": "echo \"Error: no test specified\" && exit 1" }, + "wepy": { + "module-a": false, + "./src/components/list": "./src/components/wepy-list.wpy" + }, "author": "", "license": "MIT" } diff --git a/packages/wepy-cli/templates/template/src/components/wepy-list.wpy b/packages/wepy-cli/templates/template/src/components/wepy-list.wpy new file mode 100644 index 000000000..07ac10620 --- /dev/null +++ b/packages/wepy-cli/templates/template/src/components/wepy-list.wpy @@ -0,0 +1,55 @@ + + + diff --git a/packages/wepy-cli/templates/template/src/pages/index-redux.wpy b/packages/wepy-cli/templates/template/src/pages/index-redux.wpy index b76ad3a41..8f06f82e1 100644 --- a/packages/wepy-cli/templates/template/src/pages/index-redux.wpy +++ b/packages/wepy-cli/templates/template/src/pages/index-redux.wpy @@ -84,12 +84,16 @@ import wepy from 'wepy' import { connect } from 'wepy-redux' import List from '../components/list' - import Panel from '../components/panel' + import Panel from '@/components/panel' // alias example import Counter from 'counter' // alias example + import List from '../components/list' // aliasFields example + import moduleA from 'module-a' // aliasFields ignore module example import Group from '../components/group' import Toast from 'wepy-com-toast' import testMixin from '../mixins/test' + console.log('moduleA ignored: ', moduleA) // => moduleA ignored: {} + @connect({ num (state) { return state.counter.num diff --git a/packages/wepy-cli/templates/template/src/pages/index.wpy b/packages/wepy-cli/templates/template/src/pages/index.wpy index df70212ac..07e416084 100644 --- a/packages/wepy-cli/templates/template/src/pages/index.wpy +++ b/packages/wepy-cli/templates/template/src/pages/index.wpy @@ -79,13 +79,16 @@