123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- /**
- * @fileoverview 处理插件
- */
- const path = require('path')
- const through2 = require('through2')
- const config = require('./config')
- config.plugins.sort((a, b) => {
- // editable 置于最后面
- if (a === 'editable') return 1
- if (b === 'editable') return -1
- // markdown 置于最前面
- if (a === 'markdown') return -1
- if (b === 'markdown') return 1
- // 剩余任意顺序
- return 0
- })
- // 提取和替换标签名选择器(组件中仅支持 class 选择器)
- const tagSelector = {}
- let tagI = 0
- if (config.externStyle) {
- config.externStyle = config.externStyle.replace(/[^,\s}]+(?=[^}]*{)/g, $ => {
- if (!/[a-zA-Z_]/.test($[0])) return $
- if (tagSelector[$]) return '.' + tagSelector[$]
- tagSelector[$] = '_' + tagI++
- return '.' + tagSelector[$]
- })
- }
- module.exports = {
- /**
- * @description 构建插件
- * @param {string} platform 使用平台
- */
- build (platform) {
- const builds = {} // 构建模块
- let pluginImports = '' // 插件引入
- let plugins = '' // 插件列表
- let voidTags = '' // 增加的自闭合标签
- let wxml = '' // 要引入到 node.wxml 中的内容
- let js = '' // 要引入到 node.js 中的内容
- let wxss = config.externStyle // 要引入到 node.wxss 中的内容
- const json = {} // 要引入到 node.json 中的内容
- // 收集插件中要写入模板文件的内容
- for (let i = 0; i < config.plugins.length; i++) {
- const plugin = config.plugins[i]
- let build = {}
- try {
- // 专用 build
- if (platform === 'uni-app') {
- build = require(`../plugins/${plugin}/uni-app/build.js`)
- } else {
- build = require(`../plugins/${plugin}/miniprogram/build.js`)
- }
- } catch (e) { }
- try {
- // 通用 build
- build = Object.assign(require(`../plugins/${plugin}/build.js`), build)
- } catch (e) { }
- // 可以在当前平台使用
- if (!build.platform || build.platform.includes(platform)) {
- builds[plugin] = build
- if (platform === 'uni-app') {
- plugins += plugin.replace(/-([a-z])/g, ($, $1) => $1.toUpperCase()) + ','
- pluginImports += `import ${plugin.replace(/-([a-z])/g, ($, $1) => $1.toUpperCase())} from './${plugin}/${build.main ? build.main : 'index.js'}'\n`
- } else {
- plugins += `require('./${plugin}/${build.main ? build.main : 'index.js'}'),`
- }
- if (build.template) {
- wxml += build.template.replace('wx:if', 'wx:elif').replace('v-if', 'v-else-if')
- }
- if (build.methods) {
- for (const method in build.methods) {
- js += build.methods[method].toString() + ','
- }
- }
- if (build.usingComponents) {
- Object.assign(json, build.usingComponents)
- }
- if (build.style) {
- wxss += build.style
- }
- }
- }
- // 加入其他自定义标签
- for (const item of config.customElements) {
- if (platform === 'uni-app') {
- if (item.platforms) {
- wxml += '<!-- #ifdef ' + item.platforms.join(' || ').toUpperCase() + ' -->'
- }
- voidTags += item.name + ','
- wxml += '<' + item.name + ' v-else-if="n.name==\'' + item.name + '\'" :class="n.attrs.class" :style="n.attrs.style"'
- if (item.attrs) {
- for (const attr of item.attrs) {
- wxml += ' :' + attr + '="n.attrs'
- if (attr.includes('-')) {
- wxml += '[\'' + attr + '\']"'
- } else {
- wxml += '.' + attr + '"'
- }
- }
- }
- wxml += ' />'
- if (item.platforms) {
- wxml += '<!-- #endif -->'
- }
- } else if (!item.platforms || item.platforms.join(',').toLowerCase().includes(platform)) {
- voidTags += item.name + ','
- wxml += '<' + item.name + ' wx:elif="{{n.name==\'' + item.name + '\'}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}"'
- if (item.attrs) {
- for (const attr of item.attrs) {
- wxml += ' ' + attr + '="{{n.attrs'
- if (attr.includes('-')) {
- wxml += '[\'' + attr + '\']}}"'
- } else {
- wxml += '.' + attr + '}}"'
- }
- }
- }
- wxml += ' />'
- }
- }
- return through2.obj(function (file, _, callback) {
- if (file.isBuffer()) {
- // src 目录
- if (file.base.includes('src')) {
- let content = file.contents.toString()
- if (file.basename === 'index.js' || file.basename === 'mp-html.vue') {
- // 注册插件列表
- if (platform === 'uni-app') {
- content = content.replace(/const\s*plugins\s*=\s*\[\]/, `${pluginImports}const plugins=[${plugins}]`)
- } else {
- content = content.replace(/plugins\s*=\s*\[\]/, `plugins=[${plugins}]`)
- }
- } else if (file.basename === 'parser.js') {
- // 设置标签名选择器
- content = content.replace(/tagSelector\s*=\s*{}/, `tagSelector=${JSON.stringify(tagSelector)}`)
- // 设置自闭合标签
- .replace(/voidTags\s*:\s*makeMap\('/, 'voidTags: makeMap(\'' + voidTags)
- } else if (file.basename === 'node.wxml') {
- // 引入模板
- content = content.replace(/<!--\s*insert\s*-->/, wxml)
- } else if (file.basename === 'node.js') {
- // 引入方法
- content = content.replace(/methods\s*:\s*{/, 'methods:{' + js)
- } else if (file.basename === 'node.wxss') {
- // 引入样式
- content = wxss + content
- } else if (file.basename === 'node.json') {
- // 引入组件声明
- const comps = JSON.stringify(json).slice(1, -1)
- if (comps) {
- content = content.replace(/"usingComponents"\s*:\s*{/, '"usingComponents":{' + comps + ',')
- }
- } else if (file.basename === 'node.vue') {
- // 引入 vue
- content = content.replace(/<!--\s*insert\s*-->/, wxml)
- .replace(/methods\s*:\s*{/, 'methods:{' + js)
- .replace('<style>', '<style>' + wxss.replace(/\.[a-zA-Z_][^)}]*?[{,]/g, '/deep/ $&')).replace(/,url/g, ', url')
- let importComp = ''
- let comps = ''
- for (let item in json) {
- const val = json[item]
- // 插件无法通过这种方式引入
- if (val.includes('plugin://')) continue
- item = item.replace(/-([a-z])/g, (_, $1) => $1.toUpperCase())
- importComp += 'import ' + item + " from '" + val + "'\n"
- comps += item + ',\n'
- }
- content = content.replace('<script>', '<script>\n' + importComp)
- .replace(/components\s*:\s*{/, 'components: {\n' + comps)
- } else if (file.basename === 'local.html' && wxss) {
- // 引入样式
- content = '<style>' + wxss + '</style>' + content
- }
- file.contents = Buffer.from(content)
- for (const item in builds) {
- if (builds[item].handler) {
- builds[item].handler(file, platform)
- }
- }
- } else {
- // plugins 目录
- const name = file.relative.split(path.sep)[0]
- const build = builds[name]
- // 本平台不支持使用
- if (!build || file.extname === '.md' || file.basename === 'build.js') {
- callback()
- return
- }
- // import
- if (build.import) {
- if (typeof build.import === 'string') {
- if (file.relative.includes(build.import)) {
- file.import = true
- }
- } else {
- for (let i = 0; i < build.import.length; i++) {
- if (file.relative.includes(build.import[i])) {
- file.import = true
- break
- }
- }
- }
- }
- if (build.handler) {
- build.handler(file, platform)
- }
- }
- }
- this.push(file)
- callback()
- })
- },
- /**
- * @description 引入样式文件到 node.wxss 中
- */
- importCss () {
- let css = ''
- return through2.obj(function (file, _, callback) {
- if (file.isBuffer()) {
- let content = file.contents.toString()
- // 要被引入的文件
- if (file.import) {
- css += content
- callback()
- return
- }
- // 引入到对应位置
- if (file.basename === 'node.wxss') {
- content = css + content
- } else if (file.basename === 'node.vue') {
- content = content.replace('<style>', '<style>' + css.replace(/\.[a-z_][^)}]+?[{,]/g, '/deep/ $&')).replace(/,url/g, ', url')
- } else if (file.basename === 'local.html' && css) {
- content = '<style>' + css + '</style>' + content
- }
- file.contents = Buffer.from(content)
- }
- this.push(file)
- callback()
- })
- }
- }
|