mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-24 12:45:18 +08:00
feat(ssr): experimental ssr
This commit is contained in:
parent
c761844aed
commit
787f624a11
@ -77,6 +77,7 @@
|
||||
"@vue/compiler-sfc": "^3.0.10",
|
||||
"@vue/eslint-config-standard": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"@vue/server-renderer": "^3.0.11",
|
||||
"@vue/test-utils": "^2.0.0-rc.4",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"babel-eslint": "^10.1.0",
|
||||
@ -103,9 +104,10 @@
|
||||
"vite": "^2.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@css-render/plugin-bem": "^0.15.0",
|
||||
"@css-render/plugin-bem": "^0.15.1",
|
||||
"@css-render/vue3-ssr": "^0.15.1",
|
||||
"async-validator": "^3.5.1",
|
||||
"css-render": "^0.15.0",
|
||||
"css-render": "^0.15.1",
|
||||
"date-fns": "^2.19.0",
|
||||
"evtd": "^0.2.0",
|
||||
"highlight.js": "^10.7.1",
|
||||
|
@ -13,6 +13,7 @@ import { CNode } from 'css-render'
|
||||
import type { GlobalTheme } from '../config-provider'
|
||||
import { configProviderInjectionKey } from '../config-provider/src/ConfigProvider'
|
||||
import type { ThemeCommonVars } from '../_styles/common'
|
||||
import { ssrInjectionKey } from '../ssr/context'
|
||||
|
||||
globalStyle.mount({
|
||||
id: 'naive-ui-global',
|
||||
@ -95,17 +96,24 @@ function useTheme<N, T, R> (
|
||||
props: UseThemeProps<Theme<N, T, R>>,
|
||||
clsPrefixRef?: Ref<string | undefined>
|
||||
): ComputedRef<MergedTheme<Theme<N, T, R>>> {
|
||||
const ssrAdapter = inject(ssrInjectionKey, undefined)
|
||||
if (style) {
|
||||
onBeforeMount(() => {
|
||||
const mountStyle = (): void => {
|
||||
const clsPrefix = clsPrefixRef?.value
|
||||
style.mount({
|
||||
id: clsPrefix === undefined ? mountId : clsPrefix + mountId,
|
||||
head: true,
|
||||
props: {
|
||||
bPrefix: clsPrefix ? `.${clsPrefix}-` : undefined
|
||||
}
|
||||
},
|
||||
ssr: ssrAdapter
|
||||
})
|
||||
})
|
||||
}
|
||||
if (ssrAdapter) {
|
||||
mountStyle()
|
||||
} else {
|
||||
onBeforeMount(mountStyle)
|
||||
}
|
||||
}
|
||||
const NConfigProvider = inject(configProviderInjectionKey, null)
|
||||
const mergedThemeRef = computed(() => {
|
||||
|
17
src/ssr/SsrProvider.tsx
Normal file
17
src/ssr/SsrProvider.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { defineComponent, provide } from 'vue'
|
||||
import { ssrAdapter } from '@css-render/vue3-ssr'
|
||||
import { ssrInjectionKey } from './context'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SsrProvider',
|
||||
props: {
|
||||
ssr: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
setup ({ ssr }, { slots }) {
|
||||
ssr && provide(ssrInjectionKey, ssrAdapter)
|
||||
return () => slots.default?.()
|
||||
}
|
||||
})
|
4
src/ssr/context.ts
Normal file
4
src/ssr/context.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { InjectionKey } from 'vue'
|
||||
import { ssrAdapter } from '@css-render/vue3-ssr'
|
||||
|
||||
export const ssrInjectionKey: InjectionKey<typeof ssrAdapter> = Symbol('ssr')
|
1
src/ssr/index.ts
Normal file
1
src/ssr/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as NSsrProvider } from './SsrProvider'
|
25
src/ssr/tests/SsrProvider.spec.ts
Normal file
25
src/ssr/tests/SsrProvider.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { h, createSSRApp } from 'vue'
|
||||
import { renderToString } from '@vue/server-renderer'
|
||||
import { NSsrProvider } from '../index'
|
||||
import { NButton } from '../../index'
|
||||
import { setup } from '@css-render/vue3-ssr'
|
||||
|
||||
describe('n-ssr-provider', () => {
|
||||
it('should work with import on demand', (done) => {
|
||||
const app = createSSRApp({
|
||||
render () {
|
||||
return h(NSsrProvider, null, {
|
||||
default: () =>
|
||||
h(NButton, null, {
|
||||
default: () => 'btn'
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
const { collect } = setup(app)
|
||||
renderToString(app).then((v) => {
|
||||
expect(collect() + '\n' + v).toMatchSnapshot()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
277
src/ssr/tests/__snapshots__/SsrProvider.spec.ts.snap
Normal file
277
src/ssr/tests/__snapshots__/SsrProvider.spec.ts.snap
Normal file
@ -0,0 +1,277 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`n-ssr-provider should work with import on demand 1`] = `
|
||||
"<style cssr-id=\\"nButton\\">
|
||||
.n-button {
|
||||
|
||||
font-weight: var(--font-weight);
|
||||
line-height: 1;
|
||||
font-family: inherit;
|
||||
padding: var(--padding);
|
||||
height: var(--height);
|
||||
font-size: var(--font-size);
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--text-color);
|
||||
background-color: var(--color);
|
||||
width: var(--width);
|
||||
white-space: nowrap;
|
||||
outline: none;
|
||||
position: relative;
|
||||
z-index: auto;
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
color .3s var(--bezier),
|
||||
background-color .3s var(--bezier),
|
||||
opacity .3s var(--bezier),
|
||||
border-color .3s var(--bezier);
|
||||
|
||||
}
|
||||
|
||||
.n-button.n-button--color .n-button__border {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.n-button.n-button--color.n-button--disabled .n-button__border {
|
||||
border-color: var(--border-color-disabled);
|
||||
}
|
||||
|
||||
.n-button.n-button--color:not(.n-button--disabled):focus .n-button__state-border {
|
||||
border-color: var(--border-color-focus);
|
||||
}
|
||||
|
||||
.n-button.n-button--color:not(.n-button--disabled):hover .n-button__state-border {
|
||||
border-color: var(--border-color-hover);
|
||||
}
|
||||
|
||||
.n-button.n-button--color:not(.n-button--disabled):active .n-button__state-border {
|
||||
border-color: var(--border-color-pressed);
|
||||
}
|
||||
|
||||
.n-button.n-button--color:not(.n-button--disabled).n-button--pressed .n-button__state-border {
|
||||
border-color: var(--border-color-pressed);
|
||||
}
|
||||
|
||||
.n-button.n-button--disabled {
|
||||
background-color: var(--color-disabled);
|
||||
color: var(--text-color-disabled);
|
||||
}
|
||||
|
||||
.n-button.n-button--disabled .n-button__border {
|
||||
border: var(--border-disabled);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):focus {
|
||||
background-color: var(--color-focus);
|
||||
color: var(--text-color-focus);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):focus .n-button__state-border {
|
||||
border: var(--border-focus);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):hover {
|
||||
background-color: var(--color-hover);
|
||||
color: var(--text-color-hover);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):hover .n-button__state-border {
|
||||
border: var(--border-hover);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):active {
|
||||
background-color: var(--color-pressed);
|
||||
color: var(--text-color-pressed);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled):active .n-button__state-border {
|
||||
border: var(--border-pressed);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled).n-button--pressed {
|
||||
background-color: var(--color-pressed);
|
||||
color: var(--text-color-pressed);
|
||||
}
|
||||
|
||||
.n-button:not(.n-button--disabled).n-button--pressed .n-button__state-border {
|
||||
border: var(--border-pressed);
|
||||
}
|
||||
|
||||
.n-button .n-base-wave {
|
||||
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
animation-iteration-count: 1;
|
||||
animation-duration: var(--ripple-duration);
|
||||
animation-timing-function: var(--bezier-ease-out), var(--bezier-ease-out);
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-base-wave.n-base-wave--active {
|
||||
z-index: 1;
|
||||
animation-name: button-wave-spread, button-wave-opacity;
|
||||
}
|
||||
|
||||
.n-button .n-button__border, .n-button .n-button__state-border {
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: inherit;
|
||||
transition: border-color .3s var(--bezier);
|
||||
pointer-events: none;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__border {
|
||||
border: var(--border);
|
||||
}
|
||||
|
||||
.n-button .n-button__state-border {
|
||||
border: var(--border);
|
||||
border-color: #0000;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.n-button .n-button__icon {
|
||||
|
||||
margin: var(--icon-margin);
|
||||
margin-left: 0;
|
||||
height: var(--icon-size);
|
||||
width: var(--icon-size);
|
||||
max-width: var(--icon-size);
|
||||
font-size: var(--icon-size);
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__icon .n-icon-slot {
|
||||
|
||||
height: var(--icon-size);
|
||||
width: var(--icon-size);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__icon .n-icon-slot.icon-switch-transition-enter-from, .n-button .n-button__icon .n-icon-slot.icon-switch-transition-leave-to {
|
||||
transform: translateY(-50%) scale(0.75);
|
||||
left: 0;
|
||||
top: 50%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.n-button .n-button__icon .n-icon-slot.icon-switch-transition-enter-to, .n-button .n-button__icon .n-icon-slot.icon-switch-transition-leave-from {
|
||||
transform: scale(1) translateY(-50%);
|
||||
left: 0;
|
||||
top: 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.n-button .n-button__icon .n-icon-slot.icon-switch-transition-enter-active, .n-button .n-button__icon .n-icon-slot.icon-switch-transition-leave-active {
|
||||
transform-origin: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transition: all .3s cubic-bezier(.4, 0, .2, 1) !important;
|
||||
}
|
||||
|
||||
.n-button .n-button__icon.fade-in-width-expand-transition-leave-from, .n-button .n-button__icon.fade-in-width-expand-transition-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.n-button .n-button__icon.fade-in-width-expand-transition-leave-to, .n-button .n-button__icon.fade-in-width-expand-transition-enter-from {
|
||||
|
||||
opacity: 0!important;
|
||||
margin-left: 0!important;
|
||||
margin-right: 0!important;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__icon.fade-in-width-expand-transition-leave-active {
|
||||
|
||||
overflow: hidden;
|
||||
transition:
|
||||
opacity .2s cubic-bezier(.4, 0, .2, 1),
|
||||
max-width .2s cubic-bezier(.4, 0, .2, 1) .1s,
|
||||
margin-left .2s cubic-bezier(.4, 0, .2, 1) .1s,
|
||||
margin-right .2s cubic-bezier(.4, 0, .2, 1) .1s;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__icon.fade-in-width-expand-transition-enter-active {
|
||||
|
||||
overflow: hidden;
|
||||
transition:
|
||||
opacity .2s cubic-bezier(.4, 0, .2, 1) .1s,
|
||||
max-width .2s cubic-bezier(.4, 0, .2, 1),
|
||||
margin-left .2s cubic-bezier(.4, 0, .2, 1),
|
||||
margin-right .2s cubic-bezier(.4, 0, .2, 1);
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__content {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
}
|
||||
|
||||
.n-button .n-button__content ~ .n-button__icon {
|
||||
margin: var(--icon-margin);
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.n-button.n-button--block {
|
||||
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.n-button.n-button--dashed .n-button__border, .n-button.n-button--dashed .n-button__state-border {
|
||||
border-style: dashed !important;
|
||||
}
|
||||
|
||||
.n-button.n-button--disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: var(--opacity-disabled);
|
||||
}
|
||||
|
||||
@keyframes button-wave-spread {
|
||||
from {
|
||||
box-shadow: 0 0 0.5px 0 var(--ripple-color);
|
||||
}
|
||||
to {
|
||||
box-shadow: 0 0 0.5px 4.5px var(--ripple-color);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes button-wave-opacity {
|
||||
from {
|
||||
opacity: var(--wave-opacity);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!--[--><button class=\\"n-button n-button--default-type\\" tabindex=\\"0\\" type=\\"button\\" style=\\"--bezier:cubic-bezier(.4, 0, .2, 1);--bezier-ease-out:cubic-bezier(0, 0, .2, 1);--ripple-duration:.6s;--opacity-disabled:0.5;--wave-opacity:0.6;font-weight:400;--color:#0000;--color-hover:#0000;--color-pressed:#0000;--color-focus:#0000;--color-disabled:#0000;--ripple-color:#18a058;--text-color:rgb(51, 54, 57);--text-color-hover:#36ad6a;--text-color-pressed:#0c7a43;--text-color-focus:#36ad6a;--text-color-disabled:rgb(51, 54, 57);--border:1px solid rgb(224, 224, 230);--border-hover:1px solid #36ad6a;--border-pressed:1px solid #0c7a43;--border-focus:1px solid #36ad6a;--border-disabled:1px solid rgb(224, 224, 230);--width:initial;--height:34px;--font-size:14px;--padding:0 14px;--icon-size:18px;--icon-margin:6px;--border-radius:3px;\\"><!----><!----><span class=\\"n-button__content\\">btn</span><div class=\\"n-base-wave\\"></div><div class=\\"n-button__border\\" style=\\"\\"></div><div class=\\"n-button__state-border\\" style=\\"\\"></div></button><!--]-->"
|
||||
`;
|
Loading…
Reference in New Issue
Block a user