const fs = require('fs')
|
const path = require('path')
|
const uniI18n = require('@dcloudio/uni-cli-i18n')
|
|
const {
|
removeExt,
|
normalizePath,
|
camelize,
|
capitalize,
|
isNormalPage
|
} = require('./util')
|
|
const {
|
getJson,
|
parseJson
|
} = require('./json')
|
|
let mainEntry = ''
|
let nvueMainEntry = ''
|
|
function getMainEntry () {
|
if (!mainEntry) {
|
mainEntry = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'main.ts')) ? 'main.ts' : 'main.js'
|
}
|
return mainEntry
|
}
|
|
function getNVueMainEntry () {
|
if (!nvueMainEntry) {
|
nvueMainEntry = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'main.js')) ? 'main.js' : '.main.js'
|
if (nvueMainEntry === '.main.js') {
|
fs.writeFileSync(path.resolve(process.env.UNI_INPUT_DIR, '.main.js'), '')
|
}
|
}
|
return nvueMainEntry
|
}
|
|
function getPagesJson () {
|
return processPagesJson(getJson('pages.json', true))
|
}
|
|
function parsePagesJson (content, loader) {
|
return processPagesJson(parseJson(content, true), loader)
|
}
|
|
function filterPages (pages = [], root) {
|
for (let i = pages.length - 1; i >= 0; i--) {
|
const page = pages[i]
|
if (!isValidPage(page, root)) {
|
pages.splice(i, 1)
|
}
|
}
|
}
|
|
const pagesJsonJsFileName = 'pages.js'
|
|
function processPagesJson (pagesJson, loader = {
|
addDependency: function () {}
|
}) {
|
const pagesJsonJsPath = path.resolve(process.env.UNI_INPUT_DIR, pagesJsonJsFileName)
|
if (fs.existsSync(pagesJsonJsPath)) {
|
delete require.cache[pagesJsonJsPath]
|
const pagesJsonJsFn = require(pagesJsonJsPath)
|
if (typeof pagesJsonJsFn === 'function') {
|
pagesJson = pagesJsonJsFn(pagesJson, loader)
|
if (!pagesJson) {
|
console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireReturnJsonObject')}`)
|
}
|
} else {
|
console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireExportFunction')}`)
|
}
|
}
|
// 将 subpackages 转换成 subPackages
|
if (pagesJson.subpackages && !pagesJson.subPackages) {
|
pagesJson.subPackages = pagesJson.subpackages
|
delete pagesJson.subpackages
|
}
|
|
let uniNVueEntryPagePath
|
if (pagesJson.pages && pagesJson.pages.length) { // 如果首页是 nvue
|
if (isNVuePage(pagesJson.pages[0])) {
|
uniNVueEntryPagePath = pagesJson.pages[0].path
|
}
|
}
|
// pages
|
filterPages(pagesJson.pages)
|
// subPackages
|
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
|
pagesJson.subPackages.forEach(subPackage => {
|
filterPages(subPackage.pages, subPackage.root)
|
})
|
}
|
|
if (uniNVuePages.length) { // 直接挂在 pagesJson 上
|
pagesJson.nvue = {
|
pages: uniNVuePages.reverse()
|
}
|
if (uniNVueEntryPagePath) {
|
pagesJson.nvue.entryPagePath = uniNVueEntryPagePath
|
}
|
}
|
return pagesJson
|
}
|
|
function isNVuePage (page, root = '') {
|
if (process.env.UNI_PLATFORM === 'app-plus') {
|
const pagePath = path.join(root, page.path)
|
if (fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, pagePath + '.nvue'))) { // cache一下结果?如果文件被删除,cache 就会出现错误
|
return true
|
}
|
}
|
return false
|
}
|
|
function isValidPage (page, root = '') {
|
if (typeof page === 'string' || !page.path) { // 不合法的配置
|
console.warn(uniI18n.__('cliShared.pagesJsonError', {
|
0: 'https://uniapp.dcloud.io/collocation/pages?id=pages'
|
}))
|
return false
|
}
|
let pagePath = page.path
|
|
if (pagePath.indexOf('platforms') === 0) { // 平台相关
|
if (process.env.UNI_PLATFORM === 'h5' || process.env.UNI_PLATFORM === 'web') {
|
if (!(pagePath.indexOf('platforms/h5/') === 0 || pagePath.indexOf('platforms/web/') === 0)) {
|
return false
|
}
|
} else if (process.env.UNI_PLATFORM === 'app-plus' || process.env.UNI_PLATFORM === 'app') {
|
if (!(pagePath.indexOf('platforms/app-plus/') === 0 || pagePath.indexOf('platforms/app/') === 0)) {
|
return false
|
}
|
} else if (pagePath.indexOf('platforms/' + process.env.UNI_PLATFORM) === -1) { // 非本平台
|
return false
|
}
|
}
|
|
if (
|
process.env.UNI_PLATFORM === 'app-plus' &&
|
page.style
|
) {
|
const subNVues = page.style.subNVues || (page.style['app-plus'] && page.style['app-plus'].subNVues)
|
if (Array.isArray(subNVues)) {
|
subNVues.forEach(subNVue => {
|
let subNVuePath = subNVue.path
|
if (subNVuePath) {
|
subNVuePath = subNVue.path.split('?')[0]
|
const subNVuePagePath = removeExt(path.join(root, subNVuePath))
|
process.UNI_NVUE_ENTRY[subNVuePagePath] = getNVueMainJsPath(subNVuePagePath)
|
}
|
})
|
}
|
} else {
|
page.style && (delete page.style.subNVues)
|
}
|
|
if (isNVuePage(page, root)) {
|
// 存储 nvue 相关信息
|
pagePath = normalizePath(path.join(root, pagePath))
|
|
process.UNI_NVUE_ENTRY[pagePath] = getNVueMainJsPath(pagePath)
|
|
if (process.env.UNI_USING_V3 || process.env.UNI_USING_V3_NATIVE) { // 不移除
|
page.nvue = true
|
return true
|
} else {
|
uniNVuePages.push({
|
path: pagePath + '.html',
|
style: page.style || {}
|
})
|
return false
|
}
|
}
|
|
return true
|
}
|
|
function getMainJsPath (page) {
|
return path.resolve(process.env.UNI_INPUT_DIR, getMainEntry() + '?' + JSON.stringify({
|
page: encodeURIComponent(page)
|
}))
|
}
|
|
function getNVueMainJsPath (page) {
|
return path.resolve(process.env.UNI_INPUT_DIR, getNVueMainEntry() + '?' + JSON.stringify({
|
page: encodeURIComponent(page)
|
}))
|
}
|
|
process.UNI_ENTRY = {}
|
process.UNI_NVUE_ENTRY = {}
|
|
const uniNVuePages = []
|
|
function parsePages (pagesJson, pageCallback, subPageCallback) {
|
if (!pagesJson) {
|
pagesJson = getPagesJson()
|
}
|
|
// pages
|
pagesJson.pages.forEach(page => {
|
pageCallback && pageCallback(page)
|
})
|
// subPackages
|
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
|
pagesJson.subPackages.forEach((subPackage) => {
|
const {
|
root,
|
pages
|
} = subPackage
|
pages.forEach(page => {
|
root && subPageCallback && subPageCallback(root, page, subPackage)
|
})
|
})
|
}
|
}
|
|
function parseEntry (pagesJson) {
|
const mainJsPath = path.resolve(process.env.UNI_INPUT_DIR, getMainEntry())
|
process.UNI_ENTRY = {
|
'common/main': mainJsPath
|
}
|
const manifestConfig = process.UNI_MANIFEST
|
const weixinConfig = manifestConfig['mp-weixin'] || {}
|
const independentSwitch = !!weixinConfig.independent
|
if (independentSwitch) {
|
Object.values(process.UNI_SUBPACKAGES).forEach(({
|
root,
|
independent = false
|
}) => {
|
if (root && independent) {
|
const pkgRootMainJsKey = `${root}/common/main`
|
// const pkgRootMainJsPath = `${process.env.UNI_INPUT_DIR}/${root}/main.js`;
|
process.UNI_ENTRY[pkgRootMainJsKey] = mainJsPath
|
}
|
})
|
}
|
|
process.UNI_SUB_PACKAGES_ROOT = {}
|
|
process.UNI_NVUE_ENTRY = {}
|
|
if (process.env.UNI_USING_NATIVE || process.env.UNI_USING_V3_NATIVE) {
|
process.UNI_NVUE_ENTRY['app-config'] = path.resolve(process.env.UNI_INPUT_DIR, 'pages.json')
|
process.UNI_NVUE_ENTRY['app-service'] = path.resolve(process.env.UNI_INPUT_DIR, getMainEntry())
|
}
|
|
uniNVuePages.length = 0
|
|
if (!pagesJson) {
|
pagesJson = getPagesJson() // 会检测修改 nvue entry
|
}
|
|
// pages
|
pagesJson.pages.forEach(page => {
|
if (isNormalPage(page.path)) {
|
process.UNI_ENTRY[page.path] = getMainJsPath(page.path)
|
}
|
})
|
// subPackages
|
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
|
pagesJson.subPackages.forEach(({
|
root,
|
pages
|
}) => {
|
Array.isArray(pages) && pages.forEach(page => {
|
if (root) {
|
const pagePath = normalizePath(path.join(root, page.path))
|
process.UNI_ENTRY[pagePath] = getMainJsPath(pagePath)
|
process.UNI_SUB_PACKAGES_ROOT[pagePath] = root
|
}
|
})
|
})
|
}
|
}
|
|
function parseUsingComponents (usingComponents = {}) {
|
const components = []
|
Object.keys(usingComponents).forEach(name => {
|
const identifier = capitalize(camelize(name))
|
let source = usingComponents[name]
|
if (source.indexOf('/') === 0) { // 绝对路径
|
source = '@' + source
|
} else if (source.indexOf('.') !== 0) { // 相对路径
|
source = './' + source
|
}
|
components.push({
|
name,
|
identifier,
|
source
|
})
|
})
|
return components
|
}
|
|
function generateUsingComponentsCode (usingComponents) {
|
const components = parseUsingComponents(usingComponents)
|
const importCode = []
|
const componentsCode = []
|
components.forEach(({
|
name,
|
identifier,
|
source
|
}) => {
|
importCode.push(`import ${identifier} from '${source}.vue'`)
|
componentsCode.push(`'${name}':${identifier}`)
|
})
|
if (!importCode.length) {
|
return ''
|
}
|
return `;${importCode.join(';')};exports.default.components=Object.assign({${componentsCode.join(',')}},exports.default.components||{});`
|
}
|
|
function generateGlobalUsingComponentsCode (usingComponents) {
|
const components = parseUsingComponents(usingComponents)
|
const importCode = []
|
const componentsCode = []
|
components.forEach(({
|
name,
|
identifier,
|
source
|
}) => {
|
importCode.push(`import ${identifier} from '${source}.vue'`)
|
componentsCode.push(`Vue.component('${name}',${identifier})`)
|
})
|
if (!importCode.length) {
|
return ''
|
}
|
return `${importCode.join(';')};${componentsCode.join(';')};`
|
}
|
|
function getGlobalUsingComponentsCode () {
|
const pagesJson = getPagesJson()
|
const usingComponents = pagesJson.globalStyle && pagesJson.globalStyle.usingComponents
|
if (!usingComponents) {
|
return ''
|
}
|
return generateGlobalUsingComponentsCode(usingComponents)
|
}
|
|
function getUsingComponentsCode (pagePath) {
|
const usingComponents = usingComponentsPages[pagePath]
|
if (!usingComponents) {
|
return ''
|
}
|
return generateUsingComponentsCode(usingComponents)
|
}
|
|
const usingComponentsPages = Object.create(null)
|
|
function addPageUsingComponents (pagePath, usingComponents) {
|
if (usingComponents && Object.keys(usingComponents).length) {
|
usingComponentsPages[pagePath] = usingComponents
|
}
|
}
|
// 存储自动组件
|
const autoComponentMap = {}
|
|
let lastUsingAutoImportComponentsJson = ''
|
|
let uniAutoImportComponents = []
|
|
let uniAutoImportScanComponents = []
|
|
let uniQuickAppAutoImportScanComponents = false
|
|
const isDirectory = source => fs.lstatSync(source).isDirectory()
|
|
function getAutoComponentsByDir (componentsPath, absolute = false) {
|
const components = {}
|
try {
|
if (fs.existsSync(componentsPath)) {
|
let importComponentsDir = '@/components'
|
const uniModulesDir = path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules')
|
if (!absolute && componentsPath.includes(uniModulesDir)) {
|
importComponentsDir = `@/uni_modules/${path.basename(path.dirname(componentsPath))}/components`
|
}
|
fs.readdirSync(componentsPath).forEach(name => {
|
const folder = path.resolve(componentsPath, name)
|
if (!isDirectory(folder)) {
|
return
|
}
|
const importDir = absolute ? normalizePath(folder) : `${importComponentsDir}/${name}`
|
// 读取文件夹文件列表,比对文件名(fs.existsSync在大小写不敏感的系统会匹配不准确)
|
const files = fs.readdirSync(folder)
|
if (files.includes(name + '.vue')) {
|
components[`^${name}$`] = `${importDir}/${name}.vue`
|
} else if (files.includes(name + '.nvue')) {
|
components[`^${name}$`] = `${importDir}/${name}.nvue`
|
}
|
})
|
}
|
} catch (e) {
|
console.log(e)
|
}
|
return components
|
}
|
|
function initAutoComponents () {
|
const allComponents = {}
|
const componentsDirs = [path.resolve(process.env.UNI_INPUT_DIR, 'components')]
|
global.uniModules.forEach(module => {
|
componentsDirs.push(path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules', module, 'components'))
|
})
|
componentsDirs.forEach((componentsDir) => {
|
// 根目录 components 使用相对路径,uni_modules 使用绝对路径
|
const currentComponents = getAutoComponentsByDir(componentsDir, false)
|
Object.keys(currentComponents).forEach(name => {
|
(allComponents[name] || (allComponents[name] = [])).push(currentComponents[name])
|
})
|
})
|
const components = {}
|
const conflictFiles = []
|
Object.keys(allComponents).forEach(name => {
|
const files = allComponents[name]
|
components[name] = files[0]
|
if (files.length > 1) {
|
conflictFiles.push(files)
|
}
|
})
|
if (conflictFiles.length > 0) {
|
conflictFiles.forEach(files => {
|
console.warn(uniI18n.__('cliShared.easycomConflict', {
|
0: '[' + files.map((file, index) => {
|
return file
|
}).join(',') + ']'
|
}))
|
console.log('\n')
|
})
|
}
|
return components
|
}
|
|
function initAutoImportScanComponents () {
|
const components = initAutoComponents()
|
|
const {
|
initUTSComponents
|
} = require('./uts/uts.js')
|
|
initUTSComponents(process.env.UNI_INPUT_DIR, process.env.UNI_PLATFORM).forEach((item) => {
|
components[item.pattern.source] = item.replacement.replace('\0', '').replace('?uts-proxy',
|
'/package.json?uts-proxy')
|
})
|
|
if (process.env.UNI_PLATFORM === 'quickapp-native') {
|
if (!uniQuickAppAutoImportScanComponents) {
|
uniQuickAppAutoImportScanComponents = getAutoComponentsByDir(
|
path.resolve(require.resolve('@dcloudio/uni-quickapp-native'), '../../components'),
|
true
|
)
|
}
|
// 平台内置组件优先级高
|
Object.assign(components, uniQuickAppAutoImportScanComponents)
|
}
|
|
uniAutoImportScanComponents = parseUsingAutoImportComponents(components)
|
refreshAutoComponentMap()
|
}
|
|
const _toString = Object.prototype.toString
|
|
function isPlainObject (obj) {
|
return _toString.call(obj) === '[object Object]'
|
}
|
|
function initBuiltInEasycom (components, usingAutoImportComponents) {
|
components.forEach(name => {
|
const easycomName = `^${name}$`
|
if (!usingAutoImportComponents[easycomName]) {
|
usingAutoImportComponents[easycomName] =
|
'@dcloudio/uni-cli-shared/components/' + name + '.vue'
|
}
|
})
|
}
|
|
function initAutoImportComponents (easycom = {}) {
|
let usingAutoImportComponents = easycom.custom || easycom || {}
|
if (!isPlainObject(usingAutoImportComponents)) {
|
usingAutoImportComponents = {}
|
}
|
initBuiltInEasycom(BUILT_IN_EASYCOMS, usingAutoImportComponents)
|
// 目前仅 mp-weixin 内置支持 page-meta 等组件
|
if (process.env.UNI_PLATFORM === 'mp-weixin') {} else if (process.env.UNI_PLATFORM === 'mp-alipay') {
|
initBuiltInEasycom(BUILT_IN_COMPONENTS_ALIPAY, usingAutoImportComponents)
|
} else {
|
initBuiltInEasycom(BUILT_IN_COMPONENTS, usingAutoImportComponents)
|
}
|
|
const newUsingAutoImportComponentsJson = JSON.stringify(usingAutoImportComponents)
|
if (newUsingAutoImportComponentsJson !== lastUsingAutoImportComponentsJson) {
|
lastUsingAutoImportComponentsJson = newUsingAutoImportComponentsJson
|
uniAutoImportComponents = parseUsingAutoImportComponents(usingAutoImportComponents)
|
refreshAutoComponentMap()
|
}
|
}
|
|
/**
|
* UNI_AUTO_COMPONENTS 被更新,重新刷新 map
|
*/
|
function refreshAutoComponentMap () {
|
Object.keys(autoComponentMap).forEach(name => {
|
addAutoComponent(name)
|
})
|
}
|
|
function addAutoComponent (name) {
|
let opt = uniAutoImportComponents.find(opt => opt.pattern.test(name))
|
if (!opt) {
|
opt = uniAutoImportScanComponents.find(opt => opt.pattern.test(name))
|
}
|
if (!opt) { // 不匹配
|
return (autoComponentMap[name] = true) // cache
|
}
|
return (autoComponentMap[name] = {
|
name,
|
identifier: capitalize(camelize(name + '-auto-import')),
|
source: name.replace(opt.pattern, opt.replacement)
|
})
|
}
|
|
function getAutoComponents (autoComponents) {
|
const components = []
|
autoComponents.forEach(name => {
|
let autoComponent = autoComponentMap[name]
|
if (!autoComponent) {
|
autoComponent = addAutoComponent(name)
|
}
|
if (autoComponent !== true) {
|
components.push(autoComponent)
|
}
|
})
|
return components
|
}
|
|
function parseUsingAutoImportComponents (usingAutoImportComponents) {
|
const autoImportComponents = []
|
if (usingAutoImportComponents) {
|
Object.keys(usingAutoImportComponents).forEach(pattern => {
|
const replacement = usingAutoImportComponents[pattern]
|
if (replacement && typeof replacement === 'string') {
|
autoImportComponents.push({
|
pattern: new RegExp(pattern),
|
replacement: replacement
|
})
|
}
|
})
|
}
|
return autoImportComponents
|
}
|
|
const BUILT_IN_COMPONENTS = ['page-meta', 'navigation-bar', 'uni-match-media']
|
const BUILT_IN_COMPONENTS_ALIPAY = ['navigation-bar']
|
|
const BUILT_IN_EASYCOMS = ['unicloud-db', 'uniad', 'ad-rewarded-video', 'ad-fullscreen-video', 'ad-interstitial',
|
'ad-interactive'
|
]
|
|
function isBuiltInComponent (name) { // uni-template-compiler/lib/util.js 识别微信内置组件
|
return BUILT_IN_COMPONENTS.includes(name)
|
}
|
|
function isBuiltInComponentPath (modulePath) { // 内置的 easycom 类组件
|
if (BUILT_IN_EASYCOMS.find(name => modulePath.includes(name))) {
|
return true
|
}
|
return !!BUILT_IN_COMPONENTS.find(name => modulePath.includes(name))
|
}
|
|
module.exports = {
|
isBuiltInComponent,
|
isBuiltInComponentPath,
|
getMainEntry,
|
getNVueMainEntry,
|
parsePages,
|
parseEntry,
|
getPagesJson,
|
parsePagesJson,
|
pagesJsonJsFileName,
|
getAutoComponents,
|
initAutoImportComponents,
|
initAutoImportScanComponents,
|
addPageUsingComponents,
|
getUsingComponentsCode,
|
generateUsingComponentsCode,
|
getGlobalUsingComponentsCode,
|
parseUsingAutoImportComponents,
|
generateGlobalUsingComponentsCode
|
}
|