UNPKG

3.12 kBJavaScriptView Raw
1'use strict'
2
3const t = require('@babel/types')
4
5/**
6 * hybrid 共享包
7 */
8module.exports = class HybridCommonPlugin {
9 constructor(options = {}) {
10 this.options = options
11 this.debug = options.debug
12 this.mod = {
13 style: [],
14 script: []
15 }
16
17 try {
18 this.assets = require('@mfelibs/hybrid-common/assets')
19 } catch (e) {
20 this.assets = null
21 }
22 }
23
24 apply(compiler) {
25 if (!this.assets) return
26
27 compiler.plugin('compilation', (compilation, data) => {
28 data.normalModuleFactory.plugin('parser', (parser, options) => {
29 this.resolveImport(parser)
30 this.resolveRequire(parser)
31 this.resolveMemberRequire(parser)
32 })
33
34 this.injectCommonAssets2Html(compilation)
35 })
36 }
37
38 injectCommonAssets2Html(compilation) {
39 compilation.plugin(
40 'html-webpack-plugin-before-html-generation',
41 (htmlData, callback) => {
42 // assets props [ 'publicPath', 'chunks', 'js', 'css', 'manifest' ]
43 const assets = htmlData.assets
44 const scripts = this.getAssetsUrlWithSort('script')
45 const styles = this.getAssetsUrlWithSort('style')
46
47 // @TODO 支持 image
48 assets.js = [...scripts, ...assets.js]
49 assets.css = [...styles, ...assets.css]
50
51 this.debug && console.log('common assets script', scripts)
52 this.debug && console.log('common assets style', styles)
53
54 callback(null, htmlData)
55 }
56 )
57 }
58
59 getAssetsUrlWithSort(type) {
60 return this.mod[type]
61 .sort((a, b) => {
62 return a.sort - b.sort
63 })
64 .map(asset => asset.url)
65 }
66
67 // e.g. const all = require('@mfelibs/hybrid-common')
68 resolveRequire(parser) {
69 parser.plugin('evaluate CallExpression', node => {
70 if (!this.isMatchedRequireCall(node)) return
71
72 // 默认引入全部
73 Object.keys(this.assets).forEach(a => this.addMod(a))
74
75 this.debug && console.log('CallExpression', this.mod)
76 })
77 }
78
79 // e.g. const React = require('@mfelibs/hybrid-common').React
80 resolveMemberRequire(parser) {
81 parser.plugin('evaluate MemberExpression', node => {
82 if (!this.isMatchedRequireCall(node.object)) return
83
84 if (this.assets[node.property.name]) {
85 this.addMod(node.property.name)
86
87 this.debug && console.log('MemberExpression', node.property.name)
88 }
89 })
90 }
91
92 // e.g. import { Vue } from '@mfelibs/hybrid-common'
93 resolveImport(parser) {
94 parser.plugin('import specifier', (node, source, exportName, name) => {
95 if (node.source.value !== '@mfelibs/hybrid-common') return
96
97 this.addMod(exportName)
98 this.debug && console.log('Import', exportName)
99 })
100 }
101
102 isMatchedRequireCall(node) {
103 const re = new RegExp(/@mfelibs\/hybrid-common/, 'g')
104
105 return (
106 t.isIdentifier(node.callee, { name: 'require' }) &&
107 t.isLiteral(node.arguments[0]) &&
108 !t.isTemplateLiteral(node.arguments[0]) &&
109 node.arguments[0].value.match(re)
110 )
111 }
112
113 addMod(name) {
114 const { type, url, sort } = this.assets[name]
115
116 if (this.mod[type]) {
117 this.mod[type].push({ url, sort })
118 }
119 }
120}