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