diff --git a/lerna.json b/lerna.json index eaaa6aff15..d511221f77 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "packages": [ "packages/*" ], - "version": "2.9.7" + "version": "2.9.8" } diff --git a/packages/core/@types/index.d.ts b/packages/core/@types/index.d.ts index 0b4a78ee67..76e1885a67 100644 --- a/packages/core/@types/index.d.ts +++ b/packages/core/@types/index.d.ts @@ -24,30 +24,33 @@ type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I - : never; + : never -type ArrayType = T extends Array ? R : never; +type ArrayType = T extends Array ? R : never // Mpx types type Data = object | (() => object) -export type PropType = T & ( - T extends string +export type PropType = { + __type: T +} & ( + T extends String ? StringConstructor - : T extends number + : T extends number ? NumberConstructor : T extends boolean ? BooleanConstructor : T extends any[] ? ArrayConstructor - : T extends object + : T extends object ? ObjectConstructor - : never ) + : never + ) type FullPropType = { - type: PropType; - value?: T; - optionalTypes?: PropType[]; + type: PropType + value?: T + optionalTypes?: WechatMiniprogram.Component.ShortProperty[] } interface Properties { @@ -80,27 +83,17 @@ interface WatchField { type GetDataType = T extends () => any ? ReturnType : T -type PropValueType = Def extends FullPropType - ? T - : Def extends PropType - ? T - : Def extends { - type: (...args: any[]) => infer T; - optionalType?: ((...args: any[]) => infer T)[]; - value?: infer T; - } - ? T - : Def extends (...args: any[]) => infer T - ? T - : any; - -type GetPropsType = { - readonly [K in keyof T]: PropValueType +type GetPropsType = { + readonly [K in keyof T]: T[K] extends FullPropType + ? V + : T[K] extends PropType + ? V + : WechatMiniprogram.Component.PropertyToData } type RequiredPropertyNames = { [K in keyof T]-?: T[K] extends undefined ? never : K -}[keyof T]; +}[keyof T] type RequiredPropertiesForUnion = T extends object ? Pick> : never @@ -131,7 +124,7 @@ interface Context { createIntersectionObserver: WechatMiniprogram.Component.InstanceMethods>['createIntersectionObserver'] } -interface ComponentOpt, S extends Record> extends Partial { +interface ComponentOpt, S extends Record> extends Partial { data?: D properties?: P computed?: C @@ -149,7 +142,7 @@ interface ComponentOpt, S extends Record, S extends Record> = +type PageOpt, S extends Record> = ComponentOpt & Partial @@ -286,11 +279,11 @@ interface ImplementOptions { export function toPureObject (obj: T): T -declare type PluginInstallFunction = (app: Mpx, ...options: any[]) => any; +declare type PluginInstallFunction = (app: Mpx, ...options: any[]) => any export type Plugin = PluginInstallFunction | { - install: PluginInstallFunction; -}; + install: PluginInstallFunction +} export type PluginFunction = T extends PluginInstallFunction ? T : T extends { install: infer U } ? U : never; @@ -679,7 +672,7 @@ export const ONHIDE: string export const ONRESIZE: string declare global { - const defineProps: ((props: T) => Readonly>) & (() => Readonly) + const defineProps: ((props: T) => Readonly>) & (() => Readonly) const defineOptions: = [], S extends AnyObject = {}, O extends AnyObject = {}> (opt: ThisTypedComponentOpt) => void const defineExpose: (exposed?: E) => void const useContext: () => Context diff --git a/packages/store/@types/index.d.ts b/packages/store/@types/index.d.ts index 73d8678e30..4752c1861f 100644 --- a/packages/store/@types/index.d.ts +++ b/packages/store/@types/index.d.ts @@ -6,7 +6,6 @@ type UnboxDepField = F extends keyof D ? D[F] : {} type GetReturnOrSelf = T extends (...args: any)=> infer R ? R : T interface compContext { - __mpxProxy: object; [key: string]: any } diff --git a/packages/webpack-plugin/lib/index.js b/packages/webpack-plugin/lib/index.js index 226f77fbe8..5328df02ab 100644 --- a/packages/webpack-plugin/lib/index.js +++ b/packages/webpack-plugin/lib/index.js @@ -15,6 +15,8 @@ const EntryPlugin = require('webpack/lib/EntryPlugin') const JavascriptModulesPlugin = require('webpack/lib/javascript/JavascriptModulesPlugin') const FlagEntryExportAsUsedPlugin = require('webpack/lib/FlagEntryExportAsUsedPlugin') const FileSystemInfo = require('webpack/lib/FileSystemInfo') +const ImportDependency = require('webpack/lib/dependencies/ImportDependency') +const AsyncDependenciesBlock = require('webpack/lib/AsyncDependenciesBlock') const normalize = require('./utils/normalize') const toPosix = require('./utils/to-posix') const addQuery = require('./utils/add-query') @@ -325,36 +327,31 @@ class MpxWebpackPlugin { compiler.options.resolve.plugins.push(packageEntryPlugin) compiler.options.resolve.plugins.push(new FixDescriptionInfoPlugin()) - let splitChunksPlugin - let splitChunksOptions - - if (this.options.mode !== 'web') { - const optimization = compiler.options.optimization - optimization.runtimeChunk = { - name: (entrypoint) => { - for (const packageName in mpx.independentSubpackagesMap) { - if (hasOwn(mpx.independentSubpackagesMap, packageName) && isChunkInPackage(entrypoint.name, packageName)) { - return `${packageName}/bundle` - } + const optimization = compiler.options.optimization + optimization.runtimeChunk = { + name: (entrypoint) => { + for (const packageName in mpx.independentSubpackagesMap) { + if (hasOwn(mpx.independentSubpackagesMap, packageName) && isChunkInPackage(entrypoint.name, packageName)) { + return `${packageName}/bundle` } - return 'bundle' } + return 'bundle' } - splitChunksOptions = Object.assign({ - defaultSizeTypes: ['javascript', 'unknown'], - chunks: 'all', - usedExports: optimization.usedExports === true, - minChunks: 1, - minSize: 1000, - enforceSizeThreshold: Infinity, - maxAsyncRequests: 30, - maxInitialRequests: 30, - automaticNameDelimiter: '-' - }, optimization.splitChunks) - delete optimization.splitChunks - splitChunksPlugin = new SplitChunksPlugin(splitChunksOptions) - splitChunksPlugin.apply(compiler) } + const splitChunksOptions = Object.assign({ + defaultSizeTypes: ['javascript', 'unknown'], + chunks: 'all', + usedExports: optimization.usedExports === true, + minChunks: 1, + minSize: 1000, + enforceSizeThreshold: Infinity, + maxAsyncRequests: 30, + maxInitialRequests: 30, + automaticNameDelimiter: '-' + }, optimization.splitChunks) + delete optimization.splitChunks + const splitChunksPlugin = new SplitChunksPlugin(splitChunksOptions) + splitChunksPlugin.apply(compiler) // 代理writeFile if (this.options.writeMode === 'changed') { @@ -635,7 +632,7 @@ class MpxWebpackPlugin { useRelativePath: this.options.useRelativePath, removedChunks: [], forceProxyEventRules: this.options.forceProxyEventRules, - enableRequireAsync: this.options.mode === 'wx' || (this.options.mode === 'ali' && this.options.enableAliRequireAsync), + supportRequireAsync: this.options.mode === 'wx' || this.options.mode === 'web' || (this.options.mode === 'ali' && this.options.enableAliRequireAsync), partialCompile: this.options.partialCompile, collectDynamicEntryInfo: ({ resource, packageName, filename, entryType }) => { const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || { @@ -1093,15 +1090,29 @@ class MpxWebpackPlugin { // 删除root query if (queryObj.root) request = addQuery(request, {}, false, ['root']) // 目前仅wx和ali支持require.async,ali需要开启enableAliRequireAsync,其余平台使用CommonJsAsyncDependency进行模拟抹平 - if (mpx.enableRequireAsync) { - const dep = new DynamicEntryDependency(request, 'export', '', tarRoot, '', context, range, { - isRequireAsync: true, - retryRequireAsync: !!this.options.retryRequireAsync - }) + if (mpx.supportRequireAsync) { + if (mpx.mode === 'web') { + const depBlock = new AsyncDependenciesBlock( + { + name: tarRoot + }, + expr.loc, + request + ) + const dep = new ImportDependency(request, expr.range) + dep.loc = expr.loc + depBlock.addDependency(dep) + parser.state.current.addBlock(depBlock) + } else { + const dep = new DynamicEntryDependency(request, 'export', '', tarRoot, '', context, range, { + isRequireAsync: true, + retryRequireAsync: !!this.options.retryRequireAsync + }) - parser.state.current.addPresentationalDependency(dep) - // 包含require.async的模块不能被concatenate,避免DynamicEntryDependency中无法获取模块chunk以计算相对路径 - parser.state.module.buildInfo.moduleConcatenationBailout = 'require async' + parser.state.current.addPresentationalDependency(dep) + // 包含require.async的模块不能被concatenate,避免DynamicEntryDependency中无法获取模块chunk以计算相对路径 + parser.state.module.buildInfo.moduleConcatenationBailout = 'require async' + } } else { const range = expr.range const dep = new CommonJsAsyncDependency(request, range) diff --git a/packages/webpack-plugin/lib/json-compiler/helper.js b/packages/webpack-plugin/lib/json-compiler/helper.js index 33cc2754f9..94ae2fd177 100644 --- a/packages/webpack-plugin/lib/json-compiler/helper.js +++ b/packages/webpack-plugin/lib/json-compiler/helper.js @@ -17,7 +17,7 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom const pathHash = mpx.pathHash const getOutputPath = mpx.getOutputPath const mode = mpx.mode - const enableRequireAsync = mpx.enableRequireAsync + const supportRequireAsync = mpx.supportRequireAsync const asyncSubpackageRules = mpx.asyncSubpackageRules const isUrlRequest = r => isUrlRequestRaw(r, root, externals) @@ -51,15 +51,15 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom resolve(context, component, loaderContext, (err, resource, info) => { if (err) return callback(err) const { resourcePath, queryObj } = parseRequest(resource) - let placeholder = null + let placeholder = '' if (queryObj.root) { // 删除root query resource = addQuery(resource, {}, false, ['root']) // 目前只有微信支持分包异步化 - if (enableRequireAsync) { + if (supportRequireAsync) { tarRoot = queryObj.root } - } else if (!queryObj.root && asyncSubpackageRules && enableRequireAsync) { + } else if (!queryObj.root && asyncSubpackageRules && supportRequireAsync) { for (const item of asyncSubpackageRules) { if (matchCondition(resourcePath, item)) { tarRoot = item.root @@ -97,7 +97,10 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom } const entry = getDynamicEntry(resource, 'component', outputPath, tarRoot, relativePath) - callback(null, entry, tarRoot, placeholder) + callback(null, entry, { + tarRoot, + placeholder + }) }) } diff --git a/packages/webpack-plugin/lib/json-compiler/index.js b/packages/webpack-plugin/lib/json-compiler/index.js index 470fa96375..f28b76f9a2 100644 --- a/packages/webpack-plugin/lib/json-compiler/index.js +++ b/packages/webpack-plugin/lib/json-compiler/index.js @@ -211,14 +211,14 @@ module.exports = function (content) { const processComponents = (components, context, callback) => { if (components) { async.eachOf(components, (component, name, callback) => { - processComponent(component, context, { relativePath }, (err, entry, root, placeholder) => { + processComponent(component, context, { relativePath }, (err, entry, { tarRoot, placeholder } = {}) => { if (err === RESOLVE_IGNORED_ERR) { delete components[name] return callback() } if (err) return callback(err) components[name] = entry - if (root) { + if (tarRoot) { if (placeholder) { placeholder = normalizePlaceholder(placeholder) if (placeholder.resource) { diff --git a/packages/webpack-plugin/lib/template-compiler/bind-this.js b/packages/webpack-plugin/lib/template-compiler/bind-this.js index 99a7345e21..3209fc31d6 100644 --- a/packages/webpack-plugin/lib/template-compiler/bind-this.js +++ b/packages/webpack-plugin/lib/template-compiler/bind-this.js @@ -96,12 +96,11 @@ function checkDelAndGetPath (path) { } else { delPath = current.parentPath } - } else if (t.isLogicalExpression(current.container)) { // case: a || '' + } else if (t.isLogicalExpression(current.container)) { // 只处理case: a || '' or '123' || a const key = current.key === 'left' ? 'right' : 'left' if (t.isLiteral(current.parent[key])) { delPath = current.parentPath } else { - canDel = false break } } else if (current.key === 'expression' && t.isExpressionStatement(current.parentPath)) { // dealRemove删除节点时需要 @@ -116,11 +115,23 @@ function checkDelAndGetPath (path) { // 确定是否可删除 while (!t.isBlockStatement(current) && canDel) { const { key, container } = current + if (t.isIfStatement(container) && key === 'test') { // if (a) {} + canDel = false + break + } + + if (t.isLogicalExpression(container)) { // case: a || ((b || c) && d) + ignore = true + break + } + + // case: a ??= b if ( - t.isLogicalExpression(container) || // a && b - (t.isIfStatement(container) && key === 'test') // if (a) {} + key === 'right' && + t.isAssignmentExpression(container) && + ['??=', '||=', '&&='].includes(container.operator) ) { - canDel = false + ignore = true break } @@ -166,13 +177,16 @@ function dealRemove (path, replace) { if (replace) { path.replaceWith(t.stringLiteral('')) } else { - t.validate(path, path.key, null) + if (path.inList) { + t.validate(path.parent, path.key, [null]) + } else { + t.validate(path.parent, path.key, null) + } path.remove() } delete path.needBind delete path.collectInfo - } catch (e) { - } + } catch (e) {} } module.exports = { diff --git a/packages/webpack-plugin/lib/web/processJSON.js b/packages/webpack-plugin/lib/web/processJSON.js index eaeedd99f8..e85f0dc5c2 100644 --- a/packages/webpack-plugin/lib/web/processJSON.js +++ b/packages/webpack-plugin/lib/web/processJSON.js @@ -61,7 +61,8 @@ module.exports = function (json, { customGetDynamicEntry (resource, type, outputPath, packageRoot) { return { resource, - outputPath: toPosix(path.join(packageRoot, outputPath)), + // 输出web时组件outputPath不需要拼接packageRoot + outputPath: type === 'page' ? toPosix(path.join(packageRoot, outputPath)) : outputPath, packageRoot } } @@ -297,7 +298,7 @@ module.exports = function (json, { const processComponents = (components, context, callback) => { if (components) { async.eachOf(components, (component, name, callback) => { - processComponent(component, context, {}, (err, { resource, outputPath } = {}) => { + processComponent(component, context, {}, (err, { resource, outputPath } = {}, { tarRoot } = {}) => { if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err) const { resourcePath, queryObj } = parseRequest(resource) componentsMap[resourcePath] = outputPath @@ -307,7 +308,7 @@ module.exports = function (json, { isComponent: true, outputPath }), - async: queryObj.async + async: queryObj.async || tarRoot } callback() }) diff --git a/packages/webpack-plugin/lib/web/processMainScript.js b/packages/webpack-plugin/lib/web/processMainScript.js index 42c013649a..8fcb72e5ad 100644 --- a/packages/webpack-plugin/lib/web/processMainScript.js +++ b/packages/webpack-plugin/lib/web/processMainScript.js @@ -46,7 +46,6 @@ module.exports = function (script, { output += ` import Vue from 'vue' import VueRouter from 'vue-router' import Mpx from '@mpxjs/core' - import App from ${stringifyRequest(loaderContext, addQuery(resource, { isApp: true }))} import { processAppOption, getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)} Vue.use(VueRouter)\n` @@ -64,6 +63,9 @@ module.exports = function (script, { isMain: true, globalTabBar }) + + output += `\n const App = require(${stringifyRequest(loaderContext, addQuery(resource, { isApp: true }))}).default\n` + output += ` export default processAppOption({ App, diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 7850dbd072..75e00d88f0 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@mpxjs/webpack-plugin", - "version": "2.9.7", + "version": "2.9.8", "description": "mpx compile core", "keywords": [ "mpx" diff --git a/packages/webpack-plugin/test/platform/common/bind-this.spec.js b/packages/webpack-plugin/test/platform/common/bind-this.spec.js index 439daf529a..c200e0e272 100644 --- a/packages/webpack-plugin/test/platform/common/bind-this.spec.js +++ b/packages/webpack-plugin/test/platform/common/bind-this.spec.js @@ -61,6 +61,7 @@ describe('render function simplify should correct', function () { global.currentInject.render = function (_i, _c, _r, _sc) { if (_sc("a")) {} + _sc("b"); _sc("c"); _sc("a") ? _sc("b") : _sc("c"); @@ -140,21 +141,88 @@ global.currentInject.render = function (_i, _c, _r, _sc) { obj4 || 123 || '' '456' || obj4 || '' '' || 123 || obj4 + obj5 || 123 || '' + obj5 + + obj6 + obj6 || (obj7 || '') + + a1; + b1; + c1; + a1 || b1 || c1; + + a2; + b2; + a2 || b2 || ''; + + a3; + c3 + a3 || '' + a3 || '' || c3 + + a4 + a4 || '' || '' - obj5 + 'rpx' - 'height:' + obj5 + 'rpx' - 'height' + ':' + obj5 + obj8 + obj8 + 'rpx' + 'height:' + obj8 + 'rpx' + 'height' + ':' + obj8 + + obj9 + obj10 + obj11 + obj12 + obj9 || (obj10 || obj11 && obj12) + obj12 || '' }` const res = bindThis(input, { needCollect: true, renderReduce: true }).code const output = ` global.currentInject.render = function (_i, _c, _r, _sc) { // 逻辑运算 + _sc("obj3") || ''; _sc("obj3") && _c("obj3.b"); + + _sc("obj4"); '' || 123 || _sc("obj4"); + _sc("obj5") || 123 || ''; + + _sc("obj6"); + _sc("obj6") || _sc("obj7") || ''; + + _sc("a1"); + _sc("b1"); + + _sc("c1"); - _sc("obj5") + 'rpx'; + _sc("a1") || _sc("b1") || _sc("c1"); + + _sc("a2"); + _sc("b2"); + + _sc("a2") || _sc("b2") || ''; + + _sc("a3"); + _sc("c3"); + + _sc("a3") || '' || _sc("c3"); + + _sc("a4"); + + _sc("obj8"); + "" + 'rpx'; 'height:' + "" + 'rpx'; 'height' + ':' + ""; + + _sc("obj9"); + + _sc("obj10"); + + _sc("obj11"); + + _sc("obj12"); + + _sc("obj9") || _sc("obj10") || _sc("obj11") && _sc("obj12"); };` expect(trimBlankRow(res)).toBe(trimBlankRow(output)) }) @@ -238,7 +306,7 @@ global.currentInject.render = function (_i, _c, _r, _sc) { } ` const res = bindThis(input, { renderReduce: true }) - const output = ['b', 'a', 'c', 'a', 'd', 'name', 'name2'] + const output = ['a', 'b', 'a', 'c', 'a', 'd', 'name', 'name2'] expect(res.propKeys.join('')).toBe(output.join('')) }) @@ -279,6 +347,7 @@ global.currentInject.render = function (_i, _c, _r, _sc) { this.name3[this.name2]; this.name4 && this.name4.length; + this.name4['length']; this.name5;