diff --git a/lib/compile-vue.js b/lib/compile-vue.js index debc363..0df2793 100644 --- a/lib/compile-vue.js +++ b/lib/compile-vue.js @@ -126,12 +126,16 @@ export function parseJs( .replace(/import (["'])(.*?)\1/g, function (m, q, name) { if (name.endsWith('.css') || name.endsWith('.scss')) { if (name.startsWith('@/')) { - name = name.replace('@/', '/assets/css/') + name = name.replace('@/', '/') + } + + if (isBuild) { + name = name.replace(/\.scss/, '.css') } let tmp = `style${Date.now()}` fixedStyle += `document.adoptedStyleSheets.push(${tmp})\n` - return `import ${tmp} from '${name}' assert { type: 'css' }` + return `import ${tmp} from '${name}' assert { type: 'css' }\n${tmp}.path = '${name}'` } else { if (name.startsWith('@/')) { name = name.replace('@/', '/assets/js/') @@ -159,23 +163,34 @@ export function parseJs( */ export function compileVue(file, imports, options = {}, isBuild) { let code = (fs.cat(file) || '').toString() + let CACHE = options.CACHE || {} let js = code.match(JS_EXP) let scss = code.matchAll(STYLE_EXP) let html = code.match(HTML_EXP) - let fixedStyle = '\n\n' let hash = md5(file) // console.log(typeof scss) 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>`) + if (CACHE[file]) { + CACHE[file] = { + changed: CACHE[file].js !== js || CACHE[file].html !== html, + js, + html + } + } else { + CACHE[file] = { changed: false, js, html } + } + js = parseJs(js, imports, options, isBuild).replace( 'export default {', - `${fixedStyle}export default {\n template: \`${html}\`,` + `export default {\n template: \`${html}\`,` ) if (scss.length) { @@ -187,13 +202,14 @@ export function compileVue(file, imports, options = {}, isBuild) { } return css }) + CACHE[file].css = scss.join(' ') js += ` let stylesheet = new CSSStyleSheet() stylesheet.path = '${file.slice( options.IS_MPA ? options.pagesDir.length : options.root.length )}' -stylesheet.replaceSync(\`${scss.join(' ')}\`) +stylesheet.replaceSync(\`${CACHE[file].css}\`) document.adoptedStyleSheets.push(stylesheet) ` } @@ -204,11 +220,15 @@ document.adoptedStyleSheets.push(stylesheet) /** * 解析模板html */ -export function parseHtml(html, { page, imports, entry }) { +export function parseHtml(html, { page, imports, entry }, isBuild = false) { return html .replace( '', - " " + ` \n${ + isBuild ? '' : ' ' + }` ) .replace('{{title}}', page.title || '') .replace('{{keywords}}', page.keywords || '') diff --git a/lib/dev.js b/lib/dev.js index 3c91c76..d9f18bb 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -13,6 +13,7 @@ import { COMMON_HEADERS } from './constants.js' const noc = Buffer.from('') const SERVER_OPTIONS = {} +const CACHE = {} //文件缓存, 用于hmr export default async function createServer(root = '', conf = {}) { const IS_MPA = Object.keys(conf.pages).length > 1 @@ -141,8 +142,10 @@ export default async function createServer(root = '', conf = {}) { IS_MPA, currentPage, root, - pagesDir + pagesDir, + CACHE }) + res.setHeader('content-type', MIME_TYPES.js) } break @@ -150,7 +153,12 @@ export default async function createServer(root = '', conf = {}) { case 'scss': case 'css': { - let file = join(root, pathname.replace(/^assets\/css\//, '')) + let file = join( + root, + pathname + .replace(/^assets\/css\//, '') + .replace(/^assets\/js\//, '') + ) code = compileScss(file) res.setHeader('content-type', MIME_TYPES.css) } @@ -228,33 +236,57 @@ export default async function createServer(root = '', conf = {}) { }) chokidar - .watch(root) - .on('all', (act, file) => { + .watch([root, join(root, '../index.html')]) + .on('all', (act, filePath) => { if (ready) { + let file = filePath.slice(root.length) + if (act === 'add' || act === 'change') { let ext = file.slice(file.lastIndexOf('.') + 1) - console.log(ext) switch (ext) { - case 'js': - ws.send({ action: 'reload' }) - break - case 'css': case 'scss': - ws.send({ action: 'render' }) + { + let content = fs.cat(filePath).toString() + ws.send({ action: 'render', data: { path: file, content } }) + } + break + + case 'vue': + { + // console.log('>>>>', file) + let content = compileVue(filePath, conf.imports, { + IS_MPA, + currentPage, + root, + pagesDir, + CACHE + }) + let tmp = CACHE[filePath] + // console.log(tmp); + if (tmp.changed) { + console.log('需要刷新了') + ws.send({ action: 'reload' }) + } else { + ws.send({ + action: 'render', + data: { path: file, content: tmp.css } + }) + } + } + break + + default: + ws.send({ action: 'reload' }) break } + } else if (act === 'unlink' || act === 'unlinkDir') { + ws.send({ action: 'reload' }) } } }) .on('ready', () => { ready = true - console.log('预处理完成,监听文件变化中,请勿关闭本窗口...') }) - - // setInterval(() => { - - // ws.send({action: Math.random() < 0.5 ? 'render' : 'reload',data:'hello from vue-live'}) - // }, 2000); } diff --git a/lib/prod.js b/lib/prod.js index bcd3783..52d921a 100644 --- a/lib/prod.js +++ b/lib/prod.js @@ -37,7 +37,7 @@ export default function compile(root = '', dist = '', conf = {}) { let entry = fs.cat(page.entry).toString() entry = parseJs(entry, conf.imports, { IS_MPA, currentPage }, true) - let code = parseHtml(html, { page, imports: conf.imports, entry }) + let code = parseHtml(html, { page, imports: conf.imports, entry }, true) fs.echo(code, join(dist, `${currentPage}.html`)) continue @@ -91,11 +91,14 @@ export default function compile(root = '', dist = '', conf = {}) { fs.cp(it.path, join(dist, it.name)) break - case 'scss': - case 'css': + case '.scss': + case '.css': { let code = compileScss(it.path) - fs.echo(code, join(dist, it.name)) + if (!it.name.startsWith('assets')) { + it.name = 'assets/js/' + it.name + } + fs.echo(code, join(dist, it.name.replace(/\.scss$/, '.css'))) } break diff --git a/package.json b/package.json index 5dabffc..17f854c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@bytedo/vue-live", "type": "module", - "version": "0.0.15", + "version": "0.1.0", "bin": { "vue-live": "index.js" },