Nuxt choosing layout before initialize - vue.js

I use nuxt-generate and nuxt/device package. which provides the device type but for the layout since I use nuxt-generate at first load app uses default layout. not the one provided by nuxt/device. but after i go another page it starts using correct layout. so the problem is how can i have the app use layout at first initialize. or at least change it after initialize. is there any way to do these?
this is how i try to choose layout but never works at first open.
layout (context) {
if(context.isMobile) {
return 'mobile'
} else if (context.isDesktop) {
return 'default'
}
},

when you use nuxt-generate nuxt generates a series of static html files, I don't think there is an easy way to solve this, but there can be a series of workarounds:
use nuxt in ssr mode, so that you have a way of knowing who is calling that particular resource
make a distinction at the level of routes like (/desktop/*** and /mobile/***) where both routes lead to a different layout and in the webserver configuration do a redirect on the correct route
do a middleware that redirects to the correct route /desktop /mobile, but I don't recommend it because you lose the advantage of static generation of nuxt

Related

docusaurus 2: run custom script for every page

Is it possible to run some custom script for every page?
E.g., I want to run alert(1); on every page. How can I do that without the sizzling of any components?
I know it can be done by creating jsx component and using it in every .mdx file (but every doc then should be a .mdx file). So it's not the thing I'm looking for.
Docusaurus 2 user here! 👋
Docusaurus is Server-Side Rendered and then hydrated to function as a Single Page Application. Without knowing more about what you want to achieve, I can only try to give you a general advice.
One way of achieving this is to create your own plugin, it gives you access to the execution context, such as router events.
I currently use this for analytics reporting when the user changes page. It's not yet documented, but there's a good example in the Docusaurus 2 repository in the docusaurus-plugin-google-analytics package.
Here's a fragment of what I use, this only executes when a new page is loaded, which fits my use case perfectly. There may be another lifecycle hook called when the page is hydrated that I haven't found yet.
analytics-module.js
import ExecutionEnvironment from "#docusaurus/ExecutionEnvironment";
export default (function () {
if (!ExecutionEnvironment.canUseDOM) {
return null;
}
return {
onRouteUpdate({ location }) {
_paq.push(["setCustomUrl", location.pathname]);
_paq.push(["setDocumentTitle", document.title]);
_paq.push(["trackPageView"]);
},
};
})();

Dynamic publicPath When Rendering Pages with Vue SSR

We're happy users of Vue and its server-side rendering module, Vue SSR. One of the requirements of my project is that we be able to dynamically adjust Webpack's publicPath at runtime, so that we can obtain assets from our different CDNs (we have two, one for test and one for prod).
We are able to accomplish this easily on the client-side using the __webpack_public_path__ free variable, and you can also override the publicPath within the SSR client manifest for asset URLs injected into the <head>.
Yet we continue to have issues with asset URLs that are housed directly within our templates and are rendered by SSR. For example, imagine if we had the following image within our tag:
<img src="~#/test.png" />
Our goal is that, on both the server and the client, we could adjust that URL to be prefixed how we please via publicPath. There doesn't seem to be a way to dynamically update the publicPath once the vue-ssr-server-manifest.json has been generated, the resulting URL ends up being something relative like /static/test.png or whatever we original cited in our Webpack config.
Per our project constraints, it's not possible to rebuild our SSR bundle, so we need to do this at runtime. We've tried adding placeholder values as our publicPath, e.g. __CUSTOM_WEBPACK_PUBLIC_PATH__, and replacing them in the server bundle at runtime, but that ends up being ineffective since publicPath is also embedded in other Webpack generated files.
Wondering if there is a cleaner way to achieve what we need directly via Vue SSR, or if this is something we just can't configure at runtime. Thanks for reading!
Late follow-up here, but we eventually solved this issue.
We found that setting __webpack_public_path__ globally in our Node.js process did result in the correct public path being applied to our assets in our server bundle.
Once that global is present both on the window (e.g. client-side), and globally in the node process (e.g. server-side), things started working as we wanted.
We faced similar type of problems in our webapp as well. BTW, we implemented a CDN plugin for vue.
export const CDNPlugin = {
install(Vue, { CDN, assetsManifest }) {
Vue.prototype.$cdn = {
...CDN,
asset(name) {
return `${CDN.baseUrl}${assetsManifest[name]}`;
},
resource(filepath) {
return `${CDN.baseUrl}/resources/${filepath}`;
}
};
}
};
Install this plugin both of your ssr and csr file.
Vue.use(CDNPlugin, {
CDN: { baseUrl: 'https://my.static.cdn.com' },
assetsManifest: yourAssetManifestObject,
});
And the usage of this CDN plugin inside vue template is as below
<img :src="$cdn.asset('relative/path/to/asset/style.css')">
If you think it is helping a bit, then I can share more regarding our implementation.
I spent an entire day trying to figure this out. In the end I used this:
https://github.com/agoldis/webpack-require-from
Worked like a charm, client side and server. Be aware you need to set a global.MY_BASE_URL in your node/server somewhere AND you need to inject a window.MY_BASE_URL somewhere in your HTML. Then just configure webpack.
plugins.push(new WebpackRequireFrom({variableName: 'MY_BASE_URL'}));
Similar problem occurred in my project, and finally I worked it out.
Ryan's answer really helps, but there is one thing I want to clear up. __webpack_public_path__ is a LOCAL variable in webpack bundled code, which means __webpack_public_path__ and global.__webpack_public_path__ is not the same. You need to do something like
__webpack_public_path__ = process.env.ASSET_PATH;
to specify public path (https://webpack.js.org/guides/public-path/#on-the-fly FYI).
Last, please make sure your process.env.ASSET_PATH is not undefined, maybe you have to set it manually to global in your server code.
global.process.env.ASSET_PATH = process.env.ASSET_PATH;

Best practice to dynamically choose view model based on dynamic variable using the same Aurelia route?

I know that Aurelia route modules can be specified dynamically using navigationStrategy but that does not work for my purposes because the toggle value resides in the RouterConfiguration that only runs once. I need a way to route to different views where the toggle value can change multiple times during one session. Additionally, not all routes have multiple views.
What is the best practice for routing to different views on the same route based on a dynamic value?
I've come up with a few different strategies but I'm not sure which one is the most acceptable way to do this.
Using viewPorts where the route will have a static moduleId to a view that injects the name into an instance of <router-view name="view1_index"></router-view> using a global string, e.g. 'view1' may be passed down as 'view2', etc.
Using 2 or more instances of <compose> where the route will again have a static moduleId to a view that will use a global variable to toggle an if.bind in the <compose> instances
Using canActivate in the route module and redirecting to the secondary viewport if conditions are met
Using a pipeline step in the router config to evaluate whether it should direct to a different module (if this is possible)
Which of these strategies, if any, is most accepted? If all of these are odd ways of routing to different views per route, what should be done?
What is the best practice for routing to different views on the same
route based on a dynamic value?
Compose is your best bet. It is common to pass a parameter to the route, capture the parameter in the activate(params) callback, set a variable on your view model using the params, and then use that variable to set the view-model attribute of <compose>.
Using a pipeline step in the router config to evaluate whether it
should direct to a different module (if this is possible)
This is very possible. A common use case is authentication, where you use the AuthorizeStep to check whether a user is authorized and redirect him away if he is not. See http://foreverframe.net/exploring-aurelia-pipelines/. This can be activated in the PreactivateStep as well.
Using viewPorts where the route will have a static moduleId to a view
that injects the name into an instance of using a global string, e.g. 'view1'
may be passed down as 'view2', etc.
I recommend against using viewports for anything other than associating routes to views on a certain section of the screen.
Edit:
A third option you might be interested in is returning a Redirect from your canActivate() function.
import { Redirect } from 'aurelia-router';
canActivate(params) {
let thing = this.thing = await this.service.getById(params.id);
if (!thing) {
return new Redirect('somewhere');
}
return true;
}

Can Vue-Router handle clicks from normal anchors rather than router-link?

I have a scenario where there are two major components on a page; a frame-like component that contains common functionality for many applications (including a bookmark/tab bar) and my actual application code.
Since the frame doesn't actually own the page that it's included on, it seems like it would be incorrect for it to define any routes, however the current page may define their own routes that may match one of those links. In that case, I'd like vue-router to handle those anchor clicks and navigate appropriately rather than doing a full page reload.
Here's a simplified template of what this looks like:
Frame (an external dependency for my app):
<Frame>
<TabStrip>
</TabStrip>
<slot></slot>
<Frame>
App1:
<Frame>
<App>You're looking at: {{ pageId }}!</App>
</Frame>
So when any of the app1 domain links are clicked from that tab strip, I want my route definitions in app1 to pick that up rather than it causing a page load. Since that component is owned by the frame, I don't have access to write <router-link> since links to many different apps may co-exist there.
Any thoughts?
Whoo, this is an old one! However, since this question was high in my search results when I was researching this problem, I figured I should answer it.
My use-case was similar to the one in the comments: I needed to capture normal <a> links within rendered v-html and parse them through the router (the app is rendering Markdown with a light modification that generates internal links in some cases).
Things to note about my solution:
I'm using Vue3, not Vue2; the biggest difference is that this is the new Vue3 composition-style single page component syntax, but it should be easy to backport to Vue2, if necessary, because the actual things it's doing are standard Vue.
I stripped out the markdown logic, because it doesn't have anything to do with this question.
Note the code comment! You will very likely need to design your own conditional logic for how to identify links that need to be routed vs. other links (e.g. if the application in the original question has same-origin links that aren't handled by the Vue app, then copy/pasting my solution as-is won't work).
<script setup>
import { useRouter } from "vue-router"
const router = useRouter()
const props = defineProps({
source: {
type: String,
required: true,
},
})
function handleRouteLink(event) {
const target = event.target
// IMPORTANT! This is where you need to make a decision that's appropriate
// for your application. In my case, all links using the same origin are
// guaranteed to be internal, so I simply use duck-typing for the
// properties I need and compare the origins. Logic is inverted because I
// prefer to exit early rather than nest all logic in a conditional (pure
// style choice; works fine either way, and a non-inverted conditional is
// arguably easier to read).
if (!target.pathname || !target.origin || target.origin != window.location.origin) {
return
}
// We've determined this is a link that should be routed, so cancel
// the event and push it onto the router!
event.preventDefault()
event.stopPropagation()
router.push(target.pathname)
}
</script>
<template>
<div v-html="source" #click="handleRouteLink"></div>
</template>

Can we have state base routing in Aurelia

Can we have a state base routing in Aurelia JS like angular ui router
Currently I have routes like this
root/<userid>/<feature>.
Now I am just trying to implement the same in following way
root/<userid> and feature should be pass as a parameter.The problem is that
Once the component is loaded in memory it is not getting updated on params change.
TIA
You need to configure the lifecycle to be invoked any time the URL parameters change.
See "Reusing an Existing VM" at the link below.
http://aurelia.io/hub#/doc/article/aurelia/framework/latest/cheat-sheet/7
"Since the VM's navigation life-cycle is called only once you may have problems recognizing that the user switched the route from Product A to Product B (see below). To work around this issue implement the method determineActivationStrategy in your VM and return hints for the router about what you'd like to happen."
In your view model write the following method:
determineActivationStrategy {
return activationStrategy.invokeLifecycle;
}