提交 1d3a6119 编写于 作者: fxy060608's avatar fxy060608

feat(cli): merge pages.json (uni_modules)

上级 8669a33a
const merge = require('../lib/pages-json').default
describe('shared:merge', () => {
it('merge globalStyle', () => {
const a = {
globalStyle: {
navigationBarTitleText: 'uni-app',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#ffffff',
buttons: [{
text: '分享'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}
const b = {
globalStyle: {
navigationBarTitleText: 'hello',
navigationBarBackgroundColor: '#007AFF',
'app-plus': {
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
background: '#00FF00'
}
}
}
}
}
const result = {
globalStyle: {
navigationBarTitleText: 'hello',
navigationBarBackgroundColor: '#007AFF',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}
expect(merge([a, b])).toEqual(result)
})
it('merge pages', () => {
const a = {
pages: [{
path: 'pages/index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#ffffff',
buttons: [{
text: '分享'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}]
}
const b = {
pages: [{
path: 'pages/index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
background: '#00FF00'
}
}
}
}
}, {
path: 'pages/login/login'
}]
}
const result = {
pages: [{
path: 'pages/index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}, {
path: 'pages/login/login'
}]
}
expect(merge([a, b])).toEqual(result)
})
it('merge subpackages', () => {
const a = {
subPackages: [{
root: 'pages/demo',
pages: [{
path: 'index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#ffffff',
buttons: [{
text: '分享'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}]
}]
}
const b = {
subPackages: [{
root: 'pages/demo',
pages: [{
path: 'index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
background: '#00FF00'
}
}
}
}
}, {
path: 'login/login'
}]
}, {
root: 'pages/test',
pages: [{
path: 'test/test'
}]
}]
}
const result = {
subPackages: [{
root: 'pages/demo',
pages: [{
path: 'index/index',
style: {
navigationBarTitleText: 'uni-app',
'app-plus': {
bounce: 'none',
titleNView: {
background: '#000000',
buttons: [{
text: '收藏'
}],
backButton: {
color: '#ffffff',
background: '#00FF00'
}
}
}
}
}, {
path: 'login/login'
}]
}, {
root: 'pages/test',
pages: [{
path: 'test/test'
}]
}]
}
expect(merge([a, b])).toEqual(result)
})
it('merge multi', () => {
const a = {
globalStyle: {
backgroundColorTop: '#ffffff',
navigationBarTitleText: 'uni-app'
}
}
const b = {
globalStyle: {
navigationBarTitleText: 'hello1',
navigationBarBackgroundColor: '#000000',
backgroundColor: '#ffffff'
}
}
const c = {
globalStyle: {
navigationBarTitleText: 'hello2',
navigationBarBackgroundColor: '#007AFF',
backgroundTextStyle: 'light'
}
}
const result = {
globalStyle: {
backgroundColorTop: '#ffffff',
navigationBarTitleText: 'hello2',
navigationBarBackgroundColor: '#007AFF',
backgroundTextStyle: 'light',
backgroundColor: '#ffffff'
}
}
expect(merge([a, b, c])).toEqual(result)
})
})
function mergeWith (objects, customizer) {
const [first, ...rest] = objects
let ret = first
rest.forEach(a => {
ret = mergeTo(ret, a, customizer)
})
return ret
}
function mergeTo (a, b, customizer) {
const ret = {}
Object.keys(a)
.concat(Object.keys(b))
.forEach(k => {
const v = customizer(a[k], b[k], k)
ret[k] = typeof v === 'undefined' ? a[k] : v
})
return ret
}
module.exports = mergeWith
'use strict'
Object.defineProperty(exports, '__esModule', {
value: true
})
const isArray = Array.isArray
function isPlainObject (a) {
if (a === null) {
return false
}
return typeof a === 'object'
}
function mergeWith (objects, customizer) {
const [first, ...rest] = objects
let ret = first
rest.forEach(a => {
ret = mergeTo(ret, a, customizer)
})
return ret
}
function mergeTo (a, b, customizer) {
const ret = {}
Object.keys(a)
.concat(Object.keys(b))
.forEach(k => {
const v = customizer(a[k], b[k], k)
ret[k] = typeof v === 'undefined' ? a[k] : v
})
return ret
}
function mergeWithRule (a, b, k, matchField) {
if (!isArray(a)) {
return a
}
const bMatchItems = []
const ret = a.map(aItem => {
if (!matchField) {
return aItem
}
// 暂不考虑重复
const bMatchItem = b.find(bItem => aItem[matchField] === bItem[matchField])
if (bMatchItem) {
bMatchItems.push(bMatchItem)
return mergeWith([aItem, bMatchItem], createCustomizer(k))
}
return aItem
})
return ret.concat(b.filter(bItem => !bMatchItems.includes(bItem)))
}
function customizeArray (a, b, k) {
if (k === 'pages' || k === 'subPackages.pages') {
return mergeWithRule(a, b, k, 'path')
} else if (k === 'subPackages') {
return mergeWithRule(a, b, k, 'root')
}
return b
}
function customizeObject (a, b, k) {
return mergeWith([a, b], createCustomizer(k))
}
function createCustomizer (key) {
return function customizer (a, b, k) {
const newKey = key ? `${key}.${k}` : k
if (isArray(a) && isArray(b)) {
return customizeArray(a, b, newKey)
}
if (isPlainObject(a) && isPlainObject(b)) {
return customizeObject(a, b, newKey)
}
return b
}
}
function merge (pagesJsons) {
return mergeWith(pagesJsons, createCustomizer())
}
exports.default = merge
......@@ -29,10 +29,11 @@ module.exports = {
if (!state.componentGenerics) {
state.componentGenerics = Object.create(null)
}
state.componentGenerics[componentName] = true
const attr = props || {}
attr.class = 'scoped-ref'
if (state.options.platform.name === 'mp-weixin') {
attr.class = 'scoped-ref'
}
// 返回多个节点,支持作用域插槽当作普通插槽使用
return [{
type: 'slot',
......@@ -71,8 +72,10 @@ module.exports = {
componentName = baseName + state.scopedSlots[baseName]
}
state.scopedSlots[baseName]++
parentNode.attr['generic:scoped-slots-' + slotName] = componentName
parentNode.attr['data-vue-generic'] = 'scoped'
parentNode.attr['generic:scoped-slots-' + slotName] = componentName
if (state.options.platform.name === 'mp-weixin') {
parentNode.attr['data-vue-generic'] = 'scoped'
}
if (!parentNode.attr.generic) {
parentNode.attr.generic = {}
}
......
......@@ -23,14 +23,14 @@ describe('mp:compiler-mp-weixin', () => {
it('generate scoped slot', () => {
assertCodegen(
'<foo><template slot-scope="{bar}">{{ bar.foo }}</template></foo>',
'<foo generic:scoped-slots-default="test-foo-default" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
'<foo generic:scoped-slots-default="test-foo-default" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-default')
}
)
assertCodegen(
'<foo><view slot-scope="{bar}">{{ bar.foo }}</view></foo>',
'<foo generic:scoped-slots-default="test-foo-default" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
'<foo generic:scoped-slots-default="test-foo-default" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-default')
}
......@@ -40,14 +40,14 @@ describe('mp:compiler-mp-weixin', () => {
it('generate named scoped slot', () => {
assertCodegen(
'<foo><template slot="foo" slot-scope="{bar}">{{ bar.foo }}</template></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-foo')
}
)
assertCodegen(
'<foo><view slot="foo" slot-scope="{bar}">{{ bar.foo }}</view></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-foo')
}
......@@ -57,14 +57,14 @@ describe('mp:compiler-mp-weixin', () => {
it('generate scoped slot with multiline v-if', () => {
assertCodegen(
'<foo><template v-if="\nshow\n" slot-scope="{bar}">{{ bar.foo }}</template></foo>',
'<foo generic:scoped-slots-default="test-foo-default" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
'<foo generic:scoped-slots-default="test-foo-default" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-default')
}
)
assertCodegen(
'<foo><view v-if="\nshow\n" slot="foo" slot-scope="{bar}">{{ bar.foo }}</view></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
'<foo generic:scoped-slots-foo="test-foo-foo" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'foo\']}}"></foo>',
function (res) {
expect(res.generic[0]).toBe('test-foo-foo')
}
......@@ -74,21 +74,21 @@ describe('mp:compiler-mp-weixin', () => {
it('generate scoped slot', () => {
assertCodegen(
'<slot v-bind:user="user"></slot>',
'<slot></slot><scoped-slots-default user="{{user}}" bind:__l="__l"></scoped-slots-default>',
'<slot></slot><scoped-slots-default user="{{user}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default>',
function (res) {
expect(res.componentGenerics['scoped-slots-default']).toBe(true)
}
)
assertCodegen( // TODO vue-id
'<span><slot v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default user="{{user}}" bind:__l="__l"></scoped-slots-default></block><block wx:else>{{user.lastName}}</block></label>',
'<label class="_span"><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default user="{{user}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else>{{user.lastName}}</block></label>',
function (res) {
expect(res.componentGenerics['scoped-slots-default']).toBe(true)
}
)
assertCodegen(
'<span><slot name="header" v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block wx:if="{{$slots.header}}"><slot name="header"></slot><scoped-slots-header user="{{user}}" bind:__l="__l"></scoped-slots-header></block><block wx:else>{{user.lastName}}</block></label>',
'<label class="_span"><block wx:if="{{$slots.header}}"><slot name="header"></slot><scoped-slots-header user="{{user}}" class="scoped-ref" bind:__l="__l"></scoped-slots-header></block><block wx:else>{{user.lastName}}</block></label>',
function (res) {
expect(res.componentGenerics['scoped-slots-header']).toBe(true)
}
......@@ -117,7 +117,7 @@ describe('mp:compiler-mp-weixin', () => {
<view class="red">{{label}}</view>
</slot-comp>
</view>`,
'<view><slot-comp generic:scoped-slots-test="test-slot-comp-test" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test1" vue-id="551070e6-2" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test2" vue-id="551070e6-3" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test3" vue-id="551070e6-4" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp></view>'
'<view><slot-comp generic:scoped-slots-test="test-slot-comp-test" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test1" data-vue-generic="scoped" vue-id="551070e6-2" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test2" data-vue-generic="scoped" vue-id="551070e6-3" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test3" data-vue-generic="scoped" vue-id="551070e6-4" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp></view>'
)
})
......
......@@ -30,6 +30,7 @@ function checkEmitFile (filePath, jsonObj, changedEmitFiles) {
}
module.exports = function (content, map) {
content = require('./uni_modules.js')(content)
if (this.resourceQuery) {
const params = loaderUtils.parseQuery(this.resourceQuery)
if (params) {
......
const fs = require('fs')
const path = require('path')
const {
parseJson
} = require('@dcloudio/uni-cli-shared/lib/json')
const merge = require('@dcloudio/uni-cli-shared/lib/pages-json').default
function normalizeUniModulesPagesJson (pagesJson, pluginId) {
if (Array.isArray(pagesJson.pages)) {
pagesJson.pages.forEach(page => {
page.path = 'uni_modules/' + pluginId + '/' + page.path
})
}
if (Array.isArray(pagesJson.subPackages)) {
pagesJson.subPackages.forEach(subPackage => {
subPackage.root = 'uni_modules/' + pluginId + '/' + subPackage.root
})
}
return pagesJson
}
module.exports = function parsePages (content) {
const uniModulesDir = path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules')
let plugins = []
try {
plugins = fs.readdirSync(uniModulesDir)
} catch (e) {}
const pluginPagesJsons = []
plugins.forEach(plugin => {
const pagesJsonPath = path.resolve(uniModulesDir, plugin, 'pages.json')
if (fs.existsSync(pagesJsonPath)) {
pluginPagesJsons.push(
normalizeUniModulesPagesJson(parseJson(fs.readFileSync(pagesJsonPath).toString(), true), plugin)
)
}
})
if (pluginPagesJsons.length) {
const mainPagesJson = parseJson(content, true)
const pagesJson = merge(pluginPagesJsons.concat(mainPagesJson))
if (Array.isArray(mainPagesJson.pages)) { // entry page
const entryPagePath = mainPagesJson.pages[0].path
const index = pagesJson.pages.findIndex(page => page.path === entryPagePath)
const entryPage = pagesJson.pages[index]
pagesJson.pages.splice(index, 1)
pagesJson.pages.unshift(entryPage)
}
return JSON.stringify(pagesJson)
}
return content
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册