vue-ssr(下)

vue-ssr(下)

本次主要说一下,ssr怎么配合 vue-router , vuex 如何使用。

上篇遗留问题

动态引入client.bundle.js,webpack.server.js修改

plugins: [
    new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.ssr.html'),
        filename: 'server.html',
        excludeChunks: ['server'],
        minify: false,
        client: '/client.bundle.js'
    })
]

修改后就可以去掉index.ssr.html中引入的 /client.bundle.js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!--vue-ssr-outlet-->
    <!-- ejs模板 -->
    <script src="<%=htmlWebpackPlugin.options.client%>"></script>
</body>

</html>

vue-router使用

引入vue-router
npm install vue-router
router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';

//使用插件
Vue.use(VueRouter);

//和前面一样原理导出一个函数
export default () => {
    //路由可能是懒加载情况
    const router = new VueRouter({
        mode: 'history',
        routers: [{
                path: '/',
                component: Foo
            },
            {
                path: '/bar',
                components: Bar
            }
        ]
    });
    return router
}
修改main.js
import Vue from 'vue';
import App from './App.vue';
import createRouter from './router.js'

export default () => {
    const router = createRouter();
    const app = new Vue({
        router, //注入路由系统
        render: h => h(App)
    })
    return {
        app,
        router
    }
}
修改App.vue
<template>
  <div id='app'>
    <router-link to="/">Foo</router-link>
    <router-link to="/bar">Bar</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
};
</script>
修改 server-entry.js
import createApp from './app.js';
export default (context) => {
    const {
        url
    } = context;
    return new Promise((resolve, reject) => {
        const {
            app,
            router
        } = createApp();
        //路径跳转
        router.push(url);
        //等待路由跳转完毕,组件已经准备好了触发
        router.onReady(() => {
            //路由匹配到的所有组件
            const matchComponents = router.getMatchedComponents();
            //没有可以匹配的前端路由
            if (matchComponents.length === 0) {
                return reject({
                    code: 404
                });
            } else {
                resolve(app);
            }
        })
    })
}
server.js修改

修改匹配方法,使用匹配所有路径

route.get('/(.*)', async (ctx) => {
    ctx.body = await new Promise((resolve, reject) => {
        //第一个参数对象url,是传递给server-entry.js里的context
        render.renderToString({
            url: ctx.url
        }, (err, html) => {
            if (err.code === 404) resolve('Not Found');
            resolve(html);
        })
    })
})

vuex使用

vuex在ssr中的使用,需要注意的是, 只能在路由页面中使用

引入vuex
npm install vuex
store.js
import Vue from 'vue';
import Vuex from 'vuex';

//引入插件
Vue.use(Vuex);

export default () => {
    const store = Vuex.Store({
        state: {
            count: 0
        },
        mutations: { //同步方法
            increment(state, payload) {
                state.count += payload;
            }
        },
        actions: { //异步方法
            asyncIncrement({
                commit
            }) {
                return new Promise((resolve) => {
                    setTimeout(() => {
                        commit('increment', 2);
                        resolve();
                    }, 2000)
                })
            }
        }
    })
    return store;
}
修改main.js
import Vue from 'vue';
import App from './App.vue';
import createRouter from './router.js';
import createStore from './store.js';

export default () => {
    const router = createRouter();
    const store = createStore();
    const app = new Vue({
        router,
        store,
        render: h => h(App)
    })
    return {
        app,
        store,
        router
    }
}
修改Foo.vue
<template>
  <div>
    <div>{{ $store.state.count }}</div>
  </div>
</template>
<script>
export default {
  //服务器端执行的方法
  asyncData(store) {
    console.log("111");
    return store.dispatch("asyncIncrement");
  },
  methods: {
    show() {
      alert(1);
    },
  },
};
</script>
修改server-entry.js
import createApp from './main.js';

export default (context) => {
    //当前请求路径
    const {
        url
    } = context;
    //可能存在动态路由的情况,所以这里用异步
    return new Promise((resolve, reject) => {
        const {
            app,
            router,
            store
        } = createApp();
        //路由跳转
        router.push(url);
        router.onReady(() => {
            //获取当前路径对应的所有组件
            const matchComponents = router.getMatchComponents();
            //路径下没有匹配的组件
            if (matchComponents.length === 0) {
                reject({
                    code: 404
                })
            } else {
                //有可以匹配的组件
                Promise.all(matchComponents.map(component => {
                    //判断组件下是有需要执行的asyncData
                    if (component.asyncData) {
                        return component.asyncData(store)
                    }
                })).then(() => {
                    //服务器执行完毕后,最新的状态保存在store.state上,
                    //会默认在window下生成一个变量,内部默认就这样的,"window.__INITIAL_STATE__
                    context.state = store.state;
                    resolve(app);
                })
            }
        })
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值