增加scpoed特性的支持
parent
5e6fc26bd3
commit
f5f0cbf1bc
|
@ -20,7 +20,7 @@
|
|||
- 因为没有编译过程, 一切都是基于`vue esm runtime`实时解析, 所以性能会有一定的下降(那点性能损耗一般可以忽略)。
|
||||
- 因为没有打包, 所以所有的文件引用都是按源代码的结构, 对于源码的保护比较弱(虽然打包也没约等于没保护, 因为前端没秘密)。
|
||||
- 因为是用的是原生的`ESM`,所以引用的**依赖/文件**, 需要完整的路径, 不得省略后缀名, 更不能省略`index.js/index.vue`。
|
||||
- 因为没有专门处理样式, 所以原来的`scoped`不可用, 自行使用`命名空间`的方式实现样式隔离; 相应的, vue中的 `>>>、:deep、v-deep`等功能不可用。
|
||||
- 因为没有内置完整的样式处理, 所以`scoped特性`虽然支持, 但vue中的 `>>>、:deep、v-deep`等功能不可用。
|
||||
- `单文件组件`中的样式, 如果是用scss, 不支持引用其他文件, 也不支持设置共用定义文件。
|
||||
- 样式预处理器, 只支持scss, 不支持less。
|
||||
|
||||
|
|
|
@ -6,20 +6,56 @@
|
|||
|
||||
import fs from 'iofs'
|
||||
import scss from '@bytedo/sass'
|
||||
import { createHash } from 'crypto'
|
||||
|
||||
import { JS_EXP, STYLE_EXP, HTML_EXP } from './constants.js'
|
||||
import { JS_EXP, STYLE_EXP, HTML_EXP, CSS_SHEET_EXP } from './constants.js'
|
||||
|
||||
const OPTIONS = {
|
||||
indentType: 'space',
|
||||
indentWidth: 2
|
||||
}
|
||||
|
||||
function md5(str = '') {
|
||||
let sum = createHash('md5')
|
||||
sum.update(str, 'utf8')
|
||||
return sum.digest('hex').slice(0, 8)
|
||||
}
|
||||
|
||||
function scopeCss(css, hash) {
|
||||
let rules = css.matchAll(CSS_SHEET_EXP)
|
||||
|
||||
return [...rules]
|
||||
.map(r => {
|
||||
let selector = r[1]
|
||||
let style = r[2]
|
||||
selector = selector.split(',')
|
||||
|
||||
selector = selector
|
||||
.map(s => {
|
||||
let tmp = s.split(' ')
|
||||
let last = tmp.pop()
|
||||
if (last.includes(':')) {
|
||||
last = last.replace(':', `[data-${hash}]:`)
|
||||
} else {
|
||||
last += `[data-${hash}]`
|
||||
}
|
||||
tmp.push(last)
|
||||
return tmp.join(' ')
|
||||
})
|
||||
.join(', ')
|
||||
|
||||
return selector + ` {${style}}`
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译scss为css
|
||||
* @param file <String> 文件路径或scss代码
|
||||
* @param style <String> 代码风格, expanded | compressed
|
||||
* @param mini <Boolean> 是否压缩
|
||||
*/
|
||||
export function compileScss(file, style = 'expanded') {
|
||||
export function compileScss(file, mini = true) {
|
||||
let style = mini ? 'compressed' : 'expanded'
|
||||
try {
|
||||
if (fs.isfile(file)) {
|
||||
return scss.compile(file, { style, ...OPTIONS }).css
|
||||
|
@ -117,11 +153,13 @@ export function compileVue(file, imports, options = {}, isBuild) {
|
|||
let html = code.match(HTML_EXP)
|
||||
|
||||
let fixedStyle = '\n\n'
|
||||
let hash = md5(file)
|
||||
|
||||
// console.log(typeof scss)
|
||||
scss = [...scss].flatMap(it => (it ? it[1] : ''))
|
||||
scss = [...scss].map(it => [it[0], it[1]])
|
||||
js = js ? js[1] : ''
|
||||
html = (html ? html[1] : '').replace(/`/g, '\\`').replace(/\$\{/g, '\\${')
|
||||
html = html.replace(/<([\w\-]+)([^>]*?)>/g, `<$1 data-${hash} $2>`)
|
||||
|
||||
js = parseJs(js, imports, options, isBuild).replace(
|
||||
'export default {',
|
||||
|
@ -129,12 +167,23 @@ export function compileVue(file, imports, options = {}, isBuild) {
|
|||
)
|
||||
|
||||
if (scss.length) {
|
||||
scss = scss.map(it => {
|
||||
let scoped = it[0].includes('scoped')
|
||||
let css = compileScss(it[1])
|
||||
if (scoped) {
|
||||
return scopeCss(css, hash)
|
||||
}
|
||||
return css
|
||||
})
|
||||
|
||||
js += `
|
||||
let stylesheet = new CSSStyleSheet()
|
||||
stylesheet.path = '${file.slice(options.IS_MPA ? options.pagesDir.length : options.root.length)}'
|
||||
stylesheet.replaceSync(\`${compileScss(scss.join('\n'))}\`)
|
||||
document.adoptedStyleSheets.push(stylesheet)
|
||||
`
|
||||
let stylesheet = new CSSStyleSheet()
|
||||
stylesheet.path = '${file.slice(
|
||||
options.IS_MPA ? options.pagesDir.length : options.root.length
|
||||
)}'
|
||||
stylesheet.replaceSync(\`${scss.join('\n')}\`)
|
||||
document.adoptedStyleSheets.push(stylesheet)
|
||||
`
|
||||
}
|
||||
|
||||
return js
|
||||
|
|
|
@ -8,6 +8,8 @@ export const JS_EXP = /<script[^>]*?>([\w\W]*?)<\/script>/
|
|||
export const STYLE_EXP = /<style[^>]*?>([\w\W]*?)<\/style>/g
|
||||
export const HTML_EXP = /<template[^>]*?>([\w\W]*?)<\/template>/
|
||||
|
||||
export const CSS_SHEET_EXP = /([\w\.,#\-:\(\)\[\]"'\=\s]+)\{([^\{\}]*?)\}/g
|
||||
|
||||
export const COMMON_HEADERS = {
|
||||
'Cache-Control': 'no-store'
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ export default function createServer(root = '', conf = {}) {
|
|||
currentPage = pageName
|
||||
pagesDir = dirname(conf.pages[pageName].entry)
|
||||
} else {
|
||||
ext = pathname[pathname.length - 1].split('.').pop()
|
||||
ext = pathname.at(-1).split('.').pop()
|
||||
pageName = currentPage
|
||||
}
|
||||
pathname = pathname.join('/')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@bytedo/vue-live",
|
||||
"type": "module",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"bin": {
|
||||
"vue-live": "index.js"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue