Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat support native to h5 #1410

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/core/src/platform/builtInMixins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import pageScrollMixin from './pageScrollMixin'
import componentGenericsMixin from './componentGenericsMixin'
import getTabBarMixin from './getTabBarMixin'
import pageRouteMixin from './pageRouteMixin'
import setDataMixin from './setDataMixin'

export default function getBuiltInMixins (options, type) {
let bulitInMixins = []
Expand All @@ -24,7 +25,8 @@ export default function getBuiltInMixins (options, type) {
getTabBarMixin(type),
pageRouteMixin(type),
// 由于relation可能是通过mixin注入的,不能通过当前的用户options中是否存在relations来简单判断是否注入该项mixin
relationsMixin(type)
relationsMixin(type),
setDataMixin(type)
]
} else {
// 此为差异抹平类mixins,原生模式下也需要注入也抹平平台差异
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/platform/builtInMixins/setDataMixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function setDataMixin () {
return {}
}
12 changes: 12 additions & 0 deletions packages/core/src/platform/builtInMixins/setDataMixin.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default function setDataMixin () {
return {
beforeCreate () {
Object.defineProperty(this, 'data', {
get () {
return Object.assign({}, this.$data, this.$props)
},
configurable: true
})
}
}
}
63 changes: 62 additions & 1 deletion packages/core/src/vuePlugin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { walkChildren, parseSelector, error, hasOwn } from '@mpxjs/utils'
import { walkChildren, parseSelector, error, isObject, hasOwn, isFunction } from '@mpxjs/utils'
import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
const datasetReg = /^data-(.+)$/

Expand Down Expand Up @@ -55,4 +55,65 @@ export default function install (Vue) {
Vue.prototype.createIntersectionObserver = function (options) {
return createIntersectionObserver(this, options)
}
Vue.prototype.setData = function (newData, callback) {
if (!isObject(newData)) {
error(`The data entry type of the setData method must be object, The type of data ${newData} is incorrect`)
return
}
const rawData = this.$data
Object.entries(newData).forEach(([key, value]) => {
if (key.includes('.') || key.includes('[')) {
// key 为索引的路径式设置 (如 'a.b', 'a[0].b.c')
const fullKeyItems = formatKey(key)
let target = this.$data
const lastItem = fullKeyItems.pop()

if (fullKeyItems.length > 0) {
fullKeyItems.forEach((item) => {
const nestedKey = item.name
if (item.isArray) {
if (!Array.isArray(target[nestedKey])) {
this.$set(target, nestedKey, [])
}
}
if (!hasOwn(target, nestedKey)) {
this.$set(target, nestedKey, {})
}
target = item.isArray ? target[nestedKey][item.index] : target[nestedKey]
})
}

lastItem.isArray ? this.$set(target[lastItem.name], lastItem.index, value) : target[lastItem.name] = value
} else {
// key 为正常顶层属性
if (hasOwn(rawData, key)) {
rawData[key] = value
} else {
// data 不存在属性,通过 $set 设置
this.$set(rawData, key, value)
}
}
})

function formatKey (key) {
const regex = /(\w+)(?:\[(\d+)\])?\.?/g
let match
const parsed = []
while ((match = regex.exec(key)) !== null) {
const propertyName = match[1]
const index = match[2]
const property = {
name: propertyName,
isArray: !!index,
index: index ? parseInt(index, 10) : undefined
}
parsed.push(property)
}
return parsed
}

if (callback && isFunction(callback)) {
this.$nextTick(callback.bind(this))
}
}
}
25 changes: 24 additions & 1 deletion packages/webpack-plugin/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1589,14 +1589,14 @@ try {
}
createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
}

if (mpx.mode === 'web') {
const mpxStyleOptions = queryObj.mpxStyleOptions
const firstLoader = loaders[0] ? toPosix(loaders[0].loader) : ''
const isPitcherRequest = firstLoader.includes('node_modules/vue-loader/lib/loaders/pitcher')
let cssLoaderIndex = -1
let vueStyleLoaderIndex = -1
let mpxStyleLoaderIndex = -1
let nativeLoaderIndex = -1
loaders.forEach((loader, index) => {
const currentLoader = toPosix(loader.loader)
if (currentLoader.includes('node_modules/css-loader') && cssLoaderIndex === -1) {
Expand All @@ -1605,6 +1605,8 @@ try {
vueStyleLoaderIndex = index
} else if (currentLoader.includes(styleCompilerPath) && mpxStyleLoaderIndex === -1) {
mpxStyleLoaderIndex = index
} else if (currentLoader.includes('native-loader')) {
nativeLoaderIndex = index
}
})
if (mpxStyleLoaderIndex === -1) {
Expand All @@ -1621,6 +1623,27 @@ try {
})
}
}
if (queryObj.isNative && (!loaders.length || nativeLoaderIndex !== loaders.length - 1)) {
loaders.push({
loader: require.resolve('@vue/vue-loader-v15/lib/index.js')
})
loaders.push({
loader: require.resolve(nativeLoaderPath)
})
}
} else {
let nativeLoaderIndex = -1
loaders.forEach((loader, index) => {
const currentLoader = toPosix(loader.loader)
if (currentLoader.includes('native-loader')) {
nativeLoaderIndex = index
}
})
if (queryObj.isNative && !queryObj.type && (!loaders.length || nativeLoaderIndex !== loaders.length - 1)) {
loaders.push({
loader: require.resolve(nativeLoaderPath)
})
}
}

createData.request = stringifyLoadersAndResource(loaders, createData.resource)
Expand Down
4 changes: 2 additions & 2 deletions packages/webpack-plugin/lib/json-compiler/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
outputPath = getOutputPath(resourcePath, 'component')
}
}
if (isScript(ext) && mode !== 'web') {
resource = `!!${nativeLoaderPath}!${resource}`
if (ext === '.js') {
resource = `${resource}?isNative=true`
}

const entry = getDynamicEntry(resource, 'component', outputPath, tarRoot, relativePath)
Expand Down
114 changes: 18 additions & 96 deletions packages/webpack-plugin/lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,16 @@ const parseRequest = require('./utils/parse-request')
const { matchCondition } = require('./utils/match-condition')
const addQuery = require('./utils/add-query')
const async = require('async')
const processJSON = require('./web/processJSON')
const processScript = require('./web/processScript')
const processStyles = require('./web/processStyles')
const processTemplate = require('./web/processTemplate')
const getJSONContent = require('./utils/get-json-content')
const normalize = require('./utils/normalize')
const getEntryName = require('./utils/get-entry-name')
const AppEntryDependency = require('./dependencies/AppEntryDependency')
const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
const RecordVueContentDependency = require('./dependencies/RecordVueContentDependency')
const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
const tsWatchRunLoaderFilter = require('./utils/ts-loader-watch-run-loader-filter')
const { MPX_APP_MODULE_ID } = require('./utils/const')
const path = require('path')
const processMainScript = require('./web/processMainScript')
const processWeb = require('./web')
const getRulesRunner = require('./platform')

module.exports = function (content) {
Expand Down Expand Up @@ -148,96 +143,23 @@ module.exports = function (content) {
}
// 处理mode为web时输出vue格式文件
if (mode === 'web') {
if (ctorType === 'app' && !queryObj.isApp) {
return async.waterfall([
(callback) => {
processJSON(parts.json, { loaderContext, pagesMap, componentsMap }, callback)
},
(jsonRes, callback) => {
processMainScript(parts.script, {
loaderContext,
ctorType,
srcMode,
moduleId,
isProduction,
jsonConfig: jsonRes.jsonObj,
outputPath: queryObj.outputPath || '',
localComponentsMap: jsonRes.localComponentsMap,
tabBar: jsonRes.jsonObj.tabBar,
tabBarMap: jsonRes.tabBarMap,
tabBarStr: jsonRes.tabBarStr,
localPagesMap: jsonRes.localPagesMap,
resource: this.resource
}, callback)
}
], (err, scriptRes) => {
if (err) return callback(err)
this.loaderIndex = -1
return callback(null, scriptRes.output)
})
}
// 通过RecordVueContentDependency和vueContentCache确保子request不再重复生成vueContent
const cacheContent = mpx.vueContentCache.get(filePath)
if (cacheContent) return callback(null, cacheContent)

return async.waterfall([
(callback) => {
async.parallel([
(callback) => {
processTemplate(parts.template, {
loaderContext,
hasScoped,
hasComment,
isNative,
srcMode,
moduleId,
ctorType,
usingComponents,
componentGenerics
}, callback)
},
(callback) => {
processStyles(parts.styles, {
ctorType,
autoScope,
moduleId
}, callback)
},
(callback) => {
processJSON(parts.json, {
loaderContext,
pagesMap,
componentsMap
}, callback)
}
], (err, res) => {
callback(err, res)
})
},
([templateRes, stylesRes, jsonRes], callback) => {
output += templateRes.output
output += stylesRes.output
output += jsonRes.output
processScript(parts.script, {
loaderContext,
ctorType,
srcMode,
moduleId,
isProduction,
componentGenerics,
jsonConfig: jsonRes.jsonObj,
outputPath: queryObj.outputPath || '',
builtInComponentsMap: templateRes.builtInComponentsMap,
genericsInfo: templateRes.genericsInfo,
wxsModuleMap: templateRes.wxsModuleMap,
localComponentsMap: jsonRes.localComponentsMap
}, callback)
}
], (err, scriptRes) => {
if (err) return callback(err)
output += scriptRes.output
this._module.addPresentationalDependency(new RecordVueContentDependency(filePath, output))
callback(null, output)
return processWeb({
parts,
loaderContext,
pagesMap,
componentsMap,
queryObj,
ctorType,
srcMode,
moduleId,
isProduction,
hasScoped,
hasComment,
isNative,
usingComponents,
componentGenerics,
autoScope,
callback
})
}
const moduleGraph = this._compilation.moduleGraph
Expand Down
Loading
Loading