Closed ghost closed 4 years ago
I think it would be better to wait Vue 3.0, since typescript integration with Vue 2 has many drawbacks.
I also wanted to point out this line:
https://github.com/chrisvfritz/vue-enterprise-boilerplate/blob/master/src/router/routes.js#L48
This isn't valid if your project is using TypeScript, since params
is defined as such:
params: Dictionary<string>
Thought @chrisvfritz should know about that.
@ffxsam params
is a string dictionary because they must appear in the url.
@chrisvfritz We could create a route meta
field to store the user object.
meta?: any
meta: {
authRequired: true,
beforeResolve(routeTo, routeFrom, next) {
store
// Try to fetch the user's information by their username
.dispatch('users/fetchUser', { username: routeTo.params.username })
.then((user) => {
// Add the user to the route meta, so that it can
// be provided as a prop for the view component below.
routeTo.meta ? routeTo.meta.user = user : routeTo.meta = { user }
// Continue to the route.
next()
})
.catch(() => {
// If a user with the provided username could not be
// found, redirect to the 404 page.
next({ name: '404', params: { resource: 'User' } })
})
},
},
// Set the user from route meta, once it's set in the
// beforeResolve route guard.
props: (route) => ({ user: route.meta && route.meta.user }),
@ffxsam
params
is a string dictionary because they must appear in the url.
Yes, exactly. And I'm saying that Chris's use of assigning a user object to the param throws an error in TypeScript.
@MartinTuroci No plans currently. I provide some reasons here for using Babel instead of TypeScript for this project. If you prefer not to convert to TypeScript manually, you may also enjoy some of these other scaffolding/boilerplate projects, many of which do start with TypeScript.
@ffxsam It definitely is a hack using params
this way. 😅 To make TypeScript happier, I just updated to use a tmp
object in meta
instead. It's still a hack, since meta
isn't really for temporary storage either, but until Vue Router provides a nicer way of passing data around between hooks, this is probably the best we can do.
@ffxsam Did you successfully convert this repo to a typescript project?
@beamsies Yep I did. Well, I wouldn't say I converted it verbatim.. I made some of my own changes. Why, did you need help with something?
@ffxsam Well, I really like this boilerplate and think it will be great for my app. But I also think people will question me later as to why I didn't use TS. So, I think I'm going to convert this to TS even though I think it will slow down dev time on a very tight schedule.
I've never used TS w/ Vue/Vuex.
@ffxsam I am struggling to convert this to a TS app. Is your conversion public? Thanks.
It's not public, no. But this is how I wound up modifying the router logic:
import Vue from 'vue';
import VueRouter from 'vue-router';
import VueMeta from 'vue-meta';
import NProgress from 'nprogress';
import routes, { RouteName } from './routes';
import store from '../store';
NProgress.configure({
showSpinner: false,
});
Vue.use(VueRouter);
Vue.use(VueMeta);
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
router.beforeEach((routeTo, routeFrom, next) => {
const redirectToLogin = () => {
// Pass the original route to the login component
next({ name: RouteName.LOGIN, query: { redirect: routeTo.fullPath } });
};
// If this isn't an initial page load and we're lazy loading a route
if (routeFrom.name !== null && routeTo.meta.lazy) {
// Start the route progress bar.
NProgress.start();
}
// Check if auth is required on this route
// (including nested routes).
const authRequired = routeTo.matched.some(route => route.meta.authRequired);
// If auth isn't required for the route, just continue.
if (!authRequired) return next();
/**
* Vuex doesn't think the user is logged in. Check with Cognito (and bypass
* the cache) to see if this is still a valid user, and store their user info
* in Vuex.
*/
if (!store.getters['auth/loggedIn']) {
return store.dispatch('auth/validate').then(user => {
user ? next() : redirectToLogin();
});
}
next();
});
router.beforeResolve(async (routeTo, routeFrom, next) => {
// Create a `beforeResolve` hook, which fires whenever
// `beforeRouteEnter` and `beforeRouteUpdate` would. This
// allows us to ensure data is fetched even when params change,
// but the resolved route does not. We put it in `meta` to
// indicate that it's a hook we created, rather than part of
// Vue Router (yet?).
try {
// For each matched route...
for (const route of routeTo.matched) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve, reject) => {
// If a `beforeResolve` hook is defined, call it with
// the same arguments as the `beforeEnter` hook.
if (route.meta && route.meta.beforeResolve) {
route.meta.beforeResolve(routeTo, routeFrom, (...args: any[]) => {
// If the user chose to redirect...
if (args.length) {
// If redirecting to the same route we're coming from...
if (routeFrom.name === args[0].name || args[0] === false) {
// Complete the animation of the route progress bar.
NProgress.done();
}
// Complete the redirect.
if (args[0] !== false) {
next(...args);
reject(new Error('Redirected'));
} else {
reject(new Error('Abort'));
}
} else {
next();
resolve();
}
});
} else {
// Otherwise, continue resolving the route.
next();
resolve();
}
});
}
// If a `beforeResolve` hook chose to redirect, just return.
} catch (error) {
return;
}
// If we reach this point, continue resolving the route.
// NProgress.done();
next();
});
// When each route is finished evaluating...
router.afterEach(() => {
// Complete the animation of the route progress bar.
NProgress.done();
});
export default router;
I do wanna point out that there's a bug here, and I'm not sure if it exists in @chrisvfritz's original code or not. But when I'm on a login page and I log in, the Login.vue
view/page's created()
method gets fired before it leaves that route. Not really sure what's going on there.
@ffxsam Interesting. Thanks for sharing. Did you get all the unit tests to work w/ typescript? I got this architecture converted to typescript.
Nope, I didn't really convert anything or work on tests. I just copied the code that I needed and made sure it worked with TypeScript.
Hi Chris. Do you plan on creating vue-enterprise-boilerplate with typescript? It would be pretty neat in my opinion since it is a perfect usecase for the enterprises nowadays.