Skip to content

Commit 661ebaf

Browse files
committed
支持 SNC 分割
1 parent daac7e9 commit 661ebaf

File tree

11 files changed

+207
-36
lines changed

11 files changed

+207
-36
lines changed

config/default.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ module.exports = {
1818
// 默认启用 runtime,仅允许 vue 文件内的模板
1919
vueRuntimeOnly: true,
2020
// @TODO 移除 console
21-
dropConsole: false
21+
dropConsole: false,
22+
// 分离 SNC
23+
splitSNC: false
2224
},
2325
ciConfig: {},
2426
entry: 'src/view/*/index.js',

libs/hybrid/SinaHybridPlugin.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const fs = require('fs')
44
const devalue = require('devalue')
55
const chalk = require('chalk')
66
const ConcatSource = require('webpack-sources/lib/ConcatSource')
7-
const { rootPath } = require('../../libs/utils')
7+
const { rootPath, isInstalled } = require('../../libs/utils')
88

99
/**
1010
* 生成版本文件
@@ -14,6 +14,7 @@ class SinaHybridPlugin {
1414
constructor(options) {
1515
this.options = options
1616
this.version = process.env.npm_package_version
17+
this.shouldSNCHoisting = options.splitSNC
1718
this.rewriteField = genRewriteFn([
1819
rootPath('public/manifest.json'),
1920
rootPath(`src/view/${this.options.entry}/public/manifest.json`)
@@ -35,6 +36,7 @@ class SinaHybridPlugin {
3536
compiler.plugin('compilation', compilation => {
3637
const maraCtx = compiler['maraContext'] || {}
3738

39+
this.splitSNC(compilation)
3840
this.genVersionFile(compilation)
3941
this.updateManifestVersion()
4042
this.injectDataSource(compilation, maraCtx.dataSource)
@@ -66,6 +68,31 @@ class SinaHybridPlugin {
6668
this.rewriteField('dataSource', dataSource)
6769
}
6870

71+
splitSNC(compilation) {
72+
if (!this.shouldSNCHoisting) return
73+
74+
compilation.plugin(
75+
'html-webpack-plugin-alter-asset-tags',
76+
(assets, callback) => {
77+
const idx = assets.body.findIndex(tag => {
78+
return tag.attributes.src.indexOf('__UNI_SNC__.') > -1
79+
})
80+
81+
if (idx < 0) return callback(null, assets)
82+
83+
assets.head.push({
84+
tagName: 'script',
85+
attributes: { src: assets.body[idx].attributes.src },
86+
closeTag: true
87+
})
88+
89+
assets.body.splice(idx, 1)
90+
91+
callback(null, assets)
92+
}
93+
)
94+
}
95+
6996
prependEntryCode(compilation, code) {
7097
const assets = compilation.assets
7198
const concatSource = (assets, fileName, code) => {

libs/hybrid/appSNC.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// 包名后添加任意参数,防止被 externals 排除
2+
// @TODO 使用 rollup 预编译,读取 lib 目录
3+
import appSNC from '@mfelibs/universal-framework?uni=1'
4+
5+
window['__UNI_SNC__'] = appSNC

libs/hybrid/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ const hybridDevPublish = require('./HybridDevPublish')
44
const hybridTestPublish = require('./hybridTestPublish')
55
const SinaHybridPlugin = require('./SinaHybridPlugin')
66
const HybridCommonPlugin = require('./HybridCommonPlugin')
7+
const splitSNC = require('./splitSNC')
78

89
module.exports = {
910
hybridDevPublish,
1011
hybridTestPublish,
1112
SinaHybridPlugin,
12-
HybridCommonPlugin
13+
HybridCommonPlugin,
14+
splitSNC
1315
}

libs/hybrid/splitSNC.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const path = require('path')
2+
const { getEntries } = require('../utils')
3+
const UNI_SNC = '__UNI_SNC__'
4+
const pkgName = '@mfelibs/universal-framework'
5+
6+
function splitSNC(entryGlob) {
7+
const sncPath = require.resolve(pkgName)
8+
const isSNCEntry = (context, request) => {
9+
const apiPath = path.join(path.dirname(sncPath), '/libs/apis')
10+
11+
if (!context.includes(apiPath)) return false
12+
13+
const filePath = path.resolve(context, request)
14+
15+
return sncPath.includes(filePath)
16+
}
17+
18+
const entryConf = getEntries(entryGlob)
19+
// 从主入口中排除 SNC 依赖
20+
const externals = [
21+
{
22+
[pkgName]: UNI_SNC
23+
},
24+
(context, request, callback) => {
25+
// 排除 universal 内部 apis 对自身的引用
26+
if (isSNCEntry(context, request)) {
27+
return callback(null, UNI_SNC)
28+
}
29+
30+
callback()
31+
}
32+
]
33+
34+
// 拆分 SNC,由于依赖 Promise,因此一并添加 polyfills
35+
entryConf[UNI_SNC] = [
36+
require.resolve('../../webpack/polyfills'),
37+
require.resolve('./appSNC')
38+
]
39+
40+
return { entry: entryConf, externals }
41+
}
42+
43+
module.exports = splitSNC

libs/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,15 @@ function styleLoaders(options) {
262262
return output
263263
}
264264

265+
function isInstalled(name) {
266+
try {
267+
require.resolve(name)
268+
return true
269+
} catch (e) {
270+
return false
271+
}
272+
}
273+
265274
module.exports = {
266275
styleLoaders,
267276
cssLoaders,
@@ -278,6 +287,7 @@ module.exports = {
278287
pubDate,
279288
banner,
280289
isNotEmptyArray,
290+
isInstalled,
281291
nodeModulesRegExp,
282292
ensureSlash,
283293
camelName,

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"babel-plugin-transform-decorators-legacy": "^1.3.4",
3434
"babel-preset-react-app": "^3.1.1",
3535
"babel-runtime": "^6.26.0",
36-
"browserslist": "^4.6.3",
36+
"browserslist": "^4.6.6",
3737
"case-sensitive-paths-webpack-plugin": "^2.1.2",
3838
"chalk": "^2.4.1",
3939
"copy-webpack-plugin-hash": "^5.1.4",
@@ -75,7 +75,7 @@
7575
"postcss-import": "^12.0.0",
7676
"postcss-loader": "^3.0.0",
7777
"postcss-mpvue-wxss": "^1.0.0",
78-
"postcss-preset-env": "^6.6.0",
78+
"postcss-preset-env": "^6.7.0",
7979
"postcss-url": "^8.0.0",
8080
"prerender-html-plugin": "0.0.33",
8181
"promise-polyfill": "^8.1.0",

webpack/webpack.base.conf.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
const path = require('path')
44
const config = require('../config')
55
const vueLoaderConfig = require('./loaders/vue-loader.conf')
6-
const { getEntries } = require('../libs/utils')
6+
const { getEntries, isInstalled } = require('../libs/utils')
7+
const { splitSNC } = require('../libs/hybrid')
78
const paths = config.paths
89
const tsImportPluginFactory = require('ts-import-plugin')
910

@@ -31,10 +32,31 @@ module.exports = function(entry, type) {
3132
const ASSETS = isLib ? '' : config.assetsDir
3233
const entryGlob = `src/view/${entry}/index.@(ts|js)`
3334
const { vueRuntimeOnly } = config.compiler
35+
const isHybridMode = config.build.env.raw['jsbridgeBuildType'] === 'app'
36+
const isDevOrBuildCmd = type === 'dev' || type === 'build'
37+
let entryConf = {}
38+
let externals = []
3439

35-
return {
40+
const shouldSNCHoisting =
41+
isDevOrBuildCmd &&
42+
isHybridMode &&
43+
config.compiler.splitSNC &&
44+
isInstalled('@mfelibs/universal-framework')
45+
46+
// hybrid SDK 提升,以尽快建立 jsbridge
47+
if (shouldSNCHoisting) {
48+
const sncConf = splitSNC(entryGlob)
49+
50+
// 使用拆分后的 entry 配置
51+
entryConf = sncConf.entry
52+
externals.push(...sncConf.externals)
53+
} else {
54+
entryConf = getEntries(entryGlob, require.resolve('./polyfills'))
55+
}
56+
57+
const baseConfig = {
3658
// dev, build 环境依赖 base.entry,务必提供
37-
entry: getEntries(entryGlob, require.resolve('./polyfills')),
59+
entry: entryConf,
3860
output: {
3961
path: paths.dist,
4062
// 统一使用 POSIX 风格拼接路径
@@ -175,6 +197,8 @@ module.exports = function(entry, type) {
175197
}
176198
]
177199
},
200+
plugins: [],
201+
externals: externals,
178202
// Some libraries import Node modules but don't use them in the browser.
179203
// Tell Webpack to provide empty mocks for them so importing them works.
180204
node: {
@@ -188,4 +212,18 @@ module.exports = function(entry, type) {
188212
child_process: 'empty'
189213
}
190214
}
215+
216+
if (isHybridMode) {
217+
const { SinaHybridPlugin } = require('../libs/hybrid')
218+
219+
// 确保在 copy Files 之前
220+
baseConfig.plugins.push(
221+
new SinaHybridPlugin({
222+
entry: entry,
223+
splitSNC: shouldSNCHoisting
224+
})
225+
)
226+
}
227+
228+
return baseConfig
191229
}

webpack/webpack.dev.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function parseChunks(entry) {
2323
}
2424

2525
module.exports = function({ entry }) {
26-
const baseWebpackConfig = require('./webpack.base.conf')(entry)
26+
const baseWebpackConfig = require('./webpack.base.conf')(entry, 'dev')
2727
const pagePublicDir = rootPath(`${config.paths.page}/${entry}/public`)
2828
const chunksEntry = parseChunks(entry)
2929
const { transformer, formatter } = require('../libs/resolveLoaderError')

webpack/webpack.prod.conf.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const moduleDependency = require('sinamfe-webpack-module_dependency')
1414
const { HybridCommonPlugin } = require('../libs/hybrid')
1515
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
1616
const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin')
17-
const { SinaHybridPlugin } = require('../libs/hybrid')
17+
// const { SinaHybridPlugin } = require('../libs/hybrid')
1818

1919
const config = require('../config')
2020
const { banner, rootPath, getChunks, isObject } = require('../libs/utils')
@@ -30,7 +30,7 @@ const shouldUseSourceMap = !!maraConf.sourceMap
3030
*/
3131
module.exports = function({ entry, cmd }) {
3232
const distPageDir = `${config.paths.dist}/${entry}`
33-
const baseWebpackConfig = require('./webpack.base.conf')(entry)
33+
const baseWebpackConfig = require('./webpack.base.conf')(entry, 'build')
3434
const hasHtml = fs.existsSync(`${config.paths.page}/${entry}/index.html`)
3535
const chunksEntry = getChunks(`src/view/${entry}/index.*.js`)
3636
const debugLabel = config.debug ? '.debug' : ''
@@ -157,7 +157,7 @@ module.exports = function({ entry, cmd }) {
157157

158158
// 【争议】:lib 模式禁用依赖分析?
159159
// 确保在 copy Files 之前
160-
maraConf.hybrid && new SinaHybridPlugin({ entry }),
160+
// maraConf.hybrid && new SinaHybridPlugin({ entry }),
161161
new moduleDependency({
162162
emitError: config.compiler.checkDuplicatePackage !== false
163163
}),

0 commit comments

Comments
 (0)