提交 8f04fe64 编写于 作者: fxy060608's avatar fxy060608

wip(app): nvue styler

上级 5cf14c50
...@@ -9,6 +9,7 @@ import { uniEasycomPlugin } from '../plugins/easycom' ...@@ -9,6 +9,7 @@ import { uniEasycomPlugin } from '../plugins/easycom'
import { uniManifestJsonPlugin } from '../plugins/manifestJson' import { uniManifestJsonPlugin } from '../plugins/manifestJson'
import { uniStatsPlugin } from '../plugins/stats' import { uniStatsPlugin } from '../plugins/stats'
import { uniAppNVuePlugin } from './plugin' import { uniAppNVuePlugin } from './plugin'
import { uniAppCssPlugin } from './plugins/appCss'
import { uniEsbuildPlugin } from './plugins/esbuild' import { uniEsbuildPlugin } from './plugins/esbuild'
import { uniMainJsPlugin } from './plugins/mainJs' import { uniMainJsPlugin } from './plugins/mainJs'
import { uniPagesJsonPlugin } from './plugins/pagesJson' import { uniPagesJsonPlugin } from './plugins/pagesJson'
...@@ -17,6 +18,7 @@ export { initNVueNodeTransforms } from './plugin' ...@@ -17,6 +18,7 @@ export { initNVueNodeTransforms } from './plugin'
export function initNVuePlugins() { export function initNVuePlugins() {
return [ return [
uniAppCssPlugin(),
uniEasycomPlugin({ exclude: UNI_EASYCOM_EXCLUDE }), uniEasycomPlugin({ exclude: UNI_EASYCOM_EXCLUDE }),
uniHBuilderXConsolePlugin(), uniHBuilderXConsolePlugin(),
uniMainJsPlugin(), uniMainJsPlugin(),
......
import type { Plugin } from 'vite'
import type { PluginContext, RollupError } from 'rollup'
import path from 'path'
import fs from 'fs-extra'
import qs from 'querystring'
import {
CompilerError,
parse,
SFCBlock,
SFCDescriptor,
} from '@vue/compiler-sfc'
import { hash, preNVueHtml, preNVueJs } from '@dcloudio/uni-cli-shared'
declare module '@vue/compiler-sfc' {
interface SFCDescriptor {
id: string
}
}
export const APP_CSS_JS = './app.css.js'
export function uniAppCssPlugin(): Plugin {
const inputDir = process.env.UNI_INPUT_DIR
return {
name: 'uni:app-nvue-app-style',
resolveId(id) {
if (id === APP_CSS_JS) {
return APP_CSS_JS
}
},
load(id) {
if (id === APP_CSS_JS) {
return genAppStylesCode(inputDir, this)
}
},
}
}
const defaultAppStylesCode = `export const AppStyles = []`
async function genAppStylesCode(
inputDir: string,
pluginContext: PluginContext
) {
const filename = path.resolve(inputDir, 'App.vue')
const descriptor = createAppDescriptor(filename, pluginContext)
if (!descriptor.styles.length) {
return defaultAppStylesCode
}
let stylesCode = ``
const styleVars: string[] = []
for (let i = 0; i < descriptor.styles.length; i++) {
const style = descriptor.styles[i]
const src = style.src || descriptor.filename
const attrsQuery = attrsToQuery(style.attrs, 'css')
const srcQuery = style.src ? `&src=${descriptor.id}` : ``
const query = `?vue&type=style&index=${i}${srcQuery}&inline`
const styleRequest = src + query + attrsQuery
stylesCode += `\nimport _style_${i} from ${JSON.stringify(styleRequest)}`
styleVars.push(`_style_${i}`)
}
return `${stylesCode}
export const AppStyles = [${styleVars.join(',')}]
`
}
function readAppCode(filename: string) {
if (!fs.existsSync(filename)) {
return ``
}
const source = fs.readFileSync(filename, 'utf8')
if (source.includes('#endif')) {
return preNVueJs(preNVueHtml(source))
}
return source
}
let appDescriptor: SFCDescriptor
function createAppDescriptor(
filename: string,
pluginContext: PluginContext
): SFCDescriptor {
const source = readAppCode(filename)
const id = hash(source)
if (!appDescriptor || appDescriptor.id !== id) {
const { descriptor, errors } = parse(source, {
filename,
})
descriptor.id = id
if (errors.length) {
errors.forEach((error) =>
pluginContext.error(createRollupError(filename, error))
)
}
appDescriptor = descriptor
}
return appDescriptor
}
export function createRollupError(
id: string,
error: CompilerError | SyntaxError
): RollupError {
const { message, name, stack } = error
const rollupError: RollupError = {
id,
plugin: 'vue',
message,
name,
stack,
}
if ('code' in error && error.loc) {
rollupError.loc = {
file: id,
line: error.loc.start.line,
column: error.loc.start.column,
}
}
return rollupError
}
// these are built-in query parameters so should be ignored
// if the user happen to add them as attrs
const ignoreList = ['id', 'index', 'src', 'type', 'lang', 'module']
function attrsToQuery(
attrs: SFCBlock['attrs'],
langFallback?: string,
forceLangFallback = false
): string {
let query = ``
for (const name in attrs) {
const value = attrs[name]
if (!ignoreList.includes(name)) {
query += `&${qs.escape(name)}${
value ? `=${qs.escape(String(value))}` : ``
}`
}
}
if (langFallback || attrs.lang) {
query +=
`lang` in attrs
? forceLangFallback
? `&lang.${langFallback}`
: `&lang.${attrs.lang}`
: `&lang.${langFallback}`
}
return query
}
import type { Plugin } from 'vite'
import type { BuildOptions, PluginBuild } from 'esbuild'
import path from 'path' import path from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
import debug from 'debug' import debug from 'debug'
import { transformWithEsbuild } from '@dcloudio/uni-cli-shared' import { transformWithEsbuild } from '@dcloudio/uni-cli-shared'
import type { BuildOptions, PluginBuild } from 'esbuild'
import type { Plugin } from 'vite'
import { nvueOutDir } from '../../utils' import { nvueOutDir } from '../../utils'
const debugEsbuild = debug('uni:app-nvue-esbuild') const debugEsbuild = debug('uni:app-nvue-esbuild')
export function uniEsbuildPlugin(): Plugin { export function uniEsbuildPlugin(): Plugin {
let buildOptions: BuildOptions let buildOptions: BuildOptions
const outputDir = process.env.UNI_OUTPUT_DIR const outputDir = process.env.UNI_OUTPUT_DIR
...@@ -50,8 +54,11 @@ export function uniEsbuildPlugin(): Plugin { ...@@ -50,8 +54,11 @@ export function uniEsbuildPlugin(): Plugin {
function buildNVuePage(filename: string, options: BuildOptions) { function buildNVuePage(filename: string, options: BuildOptions) {
return transformWithEsbuild( return transformWithEsbuild(
`import NVuePageComponent from './${filename}' `import App from './${filename}'
Vue.createApp(NVuePageComponent).mount('#root')`, import { AppStyles } from './app.css.js'
const app = Vue.createApp(App)
app.provide('__appStyles', Vue.useCssStyles(AppStyles))
app.mount('#root')`,
path.join(nvueOutDir(), 'main.js'), path.join(nvueOutDir(), 'main.js'),
options options
).then((res) => { ).then((res) => {
......
import { defineUniMainJsPlugin } from '@dcloudio/uni-cli-shared' import { defineUniMainJsPlugin } from '@dcloudio/uni-cli-shared'
import { APP_CSS_JS } from './appCss'
export function uniMainJsPlugin() { export function uniMainJsPlugin() {
return defineUniMainJsPlugin((opts) => { return defineUniMainJsPlugin((opts) => {
...@@ -17,7 +18,7 @@ export function uniMainJsPlugin() { ...@@ -17,7 +18,7 @@ export function uniMainJsPlugin() {
} }
} }
return { return {
code: `import './pages.json.js'`, code: `import './pages.json.js';import('${APP_CSS_JS}').then(()=>{})`,
map: { mappings: '' }, map: { mappings: '' },
} }
} }
......
...@@ -10982,39 +10982,50 @@ export function nvueFactory(exports, document) { ...@@ -10982,39 +10982,50 @@ export function nvueFactory(exports, document) {
nextSibling: node => node.nextSibling nextSibling: node => node.nextSibling
}; };
function isUndef(val) { function useCssStyles(styles) {
return val === undefined || val === null; var normalized = {};
if (isArray(styles)) {
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalized, name)) {
extend(normalized[name], style[name]);
} else {
normalized[name] = style[name];
}
});
});
}
return normalized;
} }
function parseStylesheet(_ref23) { function parseStylesheet(_ref23) {
var { var {
type type,
vnode: {
appContext
}
} = _ref23; } = _ref23;
if (!type.__styles) { if (!type.__styles) {
var { var styles = [];
styles
} = type; if (appContext) {
var normalizedStyles = {}; styles.push(appContext.provides.__appStyles);
if (isArray(styles)) {
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalizedStyles, name)) {
extend(normalizedStyles[name], style[name]);
} else {
normalizedStyles[name] = style[name];
}
});
});
} }
type.__styles = normalizedStyles; type.styles.forEach(style => styles.push(style));
type.__styles = useCssStyles(styles);
} }
return type.__styles; return type.__styles;
} }
function isUndef(val) {
return val === undefined || val === null;
}
function patchAttr(el, key, value) { function patchAttr(el, key, value) {
var instance = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var instance = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
...@@ -11527,6 +11538,7 @@ export function nvueFactory(exports, document) { ...@@ -11527,6 +11538,7 @@ export function nvueFactory(exports, document) {
unref: unref, unref: unref,
useAttrs: useAttrs, useAttrs: useAttrs,
useCssModule: useCssModule, useCssModule: useCssModule,
useCssStyles: useCssStyles,
useCssVars: useCssVars, useCssVars: useCssVars,
useSSRContext: useSSRContext, useSSRContext: useSSRContext,
useSlots: useSlots, useSlots: useSlots,
......
...@@ -9157,39 +9157,50 @@ export function nvueFactory(exports, document) { ...@@ -9157,39 +9157,50 @@ export function nvueFactory(exports, document) {
nextSibling: node => node.nextSibling nextSibling: node => node.nextSibling
}; };
function isUndef(val) { function useCssStyles(styles) {
return val === undefined || val === null; var normalized = {};
if (isArray(styles)) {
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalized, name)) {
extend(normalized[name], style[name]);
} else {
normalized[name] = style[name];
}
});
});
}
return normalized;
} }
function parseStylesheet(_ref23) { function parseStylesheet(_ref23) {
var { var {
type type,
vnode: {
appContext
}
} = _ref23; } = _ref23;
if (!type.__styles) { if (!type.__styles) {
var { var styles = [];
styles
} = type; if (appContext) {
var normalizedStyles = {}; styles.push(appContext.provides.__appStyles);
if (isArray(styles)) {
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalizedStyles, name)) {
extend(normalizedStyles[name], style[name]);
} else {
normalizedStyles[name] = style[name];
}
});
});
} }
type.__styles = normalizedStyles; type.styles.forEach(style => styles.push(style));
type.__styles = useCssStyles(styles);
} }
return type.__styles; return type.__styles;
} }
function isUndef(val) {
return val === undefined || val === null;
}
function patchAttr(el, key, value) { function patchAttr(el, key, value) {
var instance = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var instance = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
...@@ -9698,6 +9709,7 @@ export function nvueFactory(exports, document) { ...@@ -9698,6 +9709,7 @@ export function nvueFactory(exports, document) {
unref: unref, unref: unref,
useAttrs: useAttrs, useAttrs: useAttrs,
useCssModule: useCssModule, useCssModule: useCssModule,
useCssStyles: useCssStyles,
useCssVars: useCssVars, useCssVars: useCssVars,
useSSRContext: useSSRContext, useSSRContext: useSSRContext,
useSlots: useSlots, useSlots: useSlots,
......
...@@ -8875,30 +8875,38 @@ const nodeOps = { ...@@ -8875,30 +8875,38 @@ const nodeOps = {
nextSibling: node => node.nextSibling nextSibling: node => node.nextSibling
}; };
function isUndef(val) { function useCssStyles(styles) {
return val === undefined || val === null; const normalized = {};
if (isArray(styles)) {
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalized, name)) {
extend(normalized[name], style[name]);
}
else {
normalized[name] = style[name];
}
});
});
}
return normalized;
} }
function parseStylesheet({ type }) { function parseStylesheet({ type, vnode: { appContext } }) {
if (!type.__styles) { if (!type.__styles) {
const { styles } = type; const styles = [];
const normalizedStyles = {}; if (appContext) {
if (isArray(styles)) { styles.push(appContext.provides.__appStyles);
styles.forEach(style => {
Object.keys(style).forEach(name => {
if (hasOwn(normalizedStyles, name)) {
extend(normalizedStyles[name], style[name]);
}
else {
normalizedStyles[name] = style[name];
}
});
});
} }
type.__styles = normalizedStyles; type.styles.forEach(style => styles.push(style));
type.__styles = useCssStyles(styles);
} }
return type.__styles; return type.__styles;
} }
function isUndef(val) {
return val === undefined || val === null;
}
function patchAttr(el, key, value, instance = null) { function patchAttr(el, key, value, instance = null) {
if (instance) { if (instance) {
value = transformAttr(el, key, value, instance); value = transformAttr(el, key, value, instance);
...@@ -9219,4 +9227,4 @@ const createApp = ((...args) => { ...@@ -9219,4 +9227,4 @@ const createApp = ((...args) => {
return app; return app;
}); });
export { BaseTransition, Comment, EffectScope, Fragment, KeepAlive, ReactiveEffect, Static, Suspense, Teleport, Text, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compatUtils, computed$1 as computed, createApp, createBlock, createCommentVNode, createElementBlock, createBaseVNode as createElementVNode, createHydrationRenderer, createPropsRestProxy, createRenderer, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, defineEmits, defineExpose, defineProps, devtools, effect, effectScope, getCurrentInstance, getCurrentScope, getTransitionRawChildren, guardReactiveProps, h, handleError, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isMemoSame, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isShallow, isVNode, markRaw, mergeDefaults, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onScopeDispose, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, stop, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useAttrs, useCssModule, useCssVars, useSSRContext, useSlots, useTransitionState, version, warn$1 as warn, watch, watchEffect, watchPostEffect, watchSyncEffect, withAsyncContext, withCtx, withDefaults, withDirectives, withMemo, withScopeId }; export { BaseTransition, Comment, EffectScope, Fragment, KeepAlive, ReactiveEffect, Static, Suspense, Teleport, Text, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compatUtils, computed$1 as computed, createApp, createBlock, createCommentVNode, createElementBlock, createBaseVNode as createElementVNode, createHydrationRenderer, createPropsRestProxy, createRenderer, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, defineEmits, defineExpose, defineProps, devtools, effect, effectScope, getCurrentInstance, getCurrentScope, getTransitionRawChildren, guardReactiveProps, h, handleError, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isMemoSame, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isShallow, isVNode, markRaw, mergeDefaults, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onScopeDispose, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, stop, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useAttrs, useCssModule, useCssStyles, useCssVars, useSSRContext, useSlots, useTransitionState, version, warn$1 as warn, watch, watchEffect, watchPostEffect, watchSyncEffect, withAsyncContext, withCtx, withDefaults, withDirectives, withMemo, withScopeId };
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册