How can I load my static data in a single location within a nuxt/vue app?
Ideally I would have a JSON file holding all this data which would get loaded into vuex and would be accessible anywhere...
I've been suggested 2 options, but I don't find them clean...
When using the webpack template (not webpack-simple), you can use environment variables for that: http://vuejs-templates.github.io/webpack/env.html.
Alternatively, you can always just create some file - constants.js - anywhere in your project folder, which you use to store your static data (e.g. export const API_URL = 'https:/my-api.com' ).
Import the data from that file anywhere you need it (e.g. import { API_URL } from 'path/to/constants' ).
I've found an elegant solution using vue prototype
Hence with Nuxt.js
1) Create a plugin at ~/plugins/globals.js
import Vue from 'vue'
import globals from '~/globals.json'
import _get from 'lodash/get'
Vue.prototype.$g = (key) => {
let val = _get(globals, key, '')
if (!val) console.warn(key, ' is empty in $g')
return val || key
}
2) Create your json file at ~/global.json
{
"website_url": "https://www.company.com",
"social": {
"facebook": {
"url": "https://www.facebook.com/company"
},
"twitter": {
"url": "https://www.twitter.com/company"
}
}
}
3) Use these in every .vue file
<template>
<div>
<p>URL: {{ $g('website_url') }}</p>
<p>Facebook: {{ fburl }}</p>
<p><a :href="$g('social.twitter.url')">twitter</a></p>
</div>
</template>
<script>
export default {
data () {
return {
fburl: this.$g('social.facebook.url')
}
}
}
</script>
I found one easiest way to set configs (json) file and and use in any component.
Steps -
Create setting.json file in root directory.
in middleware, create a file settings.js (or keep any name) and paste this code
import settings from '../settings.json'
export default function ({ store, route, redirect, req}) {
process.env = settings
}
3 in nuxt.config.js - add settings in
router: {
middleware: ['users', 'settings']
},
uses -
In any component or page -
data(){
return {
settings: process.env
}
},
Now you can use settings anywhere in component.
Related
possibly a very simple question: I need to get a configuration value from within an html block in a vue file.
I have this simple config.js
const env = process.env.NODE_ENV
const development = {
images: {
server: "http://localhost:4001",
}
}
const production = {
images: {
server: "http://someimageserver.com",
}
}
const config = {
development,
production,
}
module.exports = config[env]
And this simple vue.js
<template>
<div>
<img :src="`${config.images.server}/images/someimage.jpg`"/>
</div>
</template>
At run time, the above throws
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'images')
What should I do to make this work ?
Thanks in advance
Note: I can get configuration values from within the script block using, this works perfectly, for example
import config from "../../config"
...
var c = config.images.server
UPDATE:
Using vue 3, one can easily achieve this by adding
import config from "../config"
app.config.globalProperties.$config = config
to the main.js file. From there on, $config can be used in templates and scripts across all files. Source: https://v3-migration.vuejs.org/breaking-changes/global-api.html#vue-prototype-replaced-by-config-globalproperties
In Vue, you need to initiate a variable and assign what you imported to it, and eventually return this variable. It looks like below:
Vue2:
import config from "../../config"
export default {
data() {
return {
config: config
}
}
}
Vue3:
import config from "../../config"
export default {
setup() {
return {
config
}
}
}
Then the url in the template should work fine.
-------------------------updates-----------------------
If you want to use config globally, you can register it as a Plugin.
Create plugin.js
import config from "../../config"
export const Config = {
install(Vue, options) {
Vue.prototype.$config = function() {
return config
}
}
}
Then, in your main.js, add below code
import * as Plugins from '#/plugin.js'
Vue.use(Plugins.Config.install)
Then you can use $config within templetes like $route without any other import. Surely you can write other global functions in plugin.js and register each of them in main.js.
I wrote a Rollup plugin to import Pug as an HTML string:
// Rollup plugin imported to Vite config
import { render } from 'pug';
export default function pug() {
return {
name: 'rollup-plugin-pug-html',
transform(src, id) {
if (id.endsWith('.pug')) {
const html = render(src, { filename: id });
const code = `export default ${JSON.stringify(html)};`;
return { code };
}
},
};
}
I'm using it in Vite to create templates for Vue components, as in this reduced example:
// ProofOfConceptSFC.vue
<script>
import { compile } from 'vue/dist/vue.esm-bundler.js';
import template from './template.pug';
export default {
render: compile(template)
};
</script>
The HMR is working great when I edit template.pug. The new template appears and the latest reactive values persist.
My problem is that template.pug may depend on other Pug files with include:
//- template.pug
include ./header.pug
p Hello {{ name }}
include ./footer.pug
The Vite server doesn't know about those files, and nothing happens if I touch them. Ideally I could invalidate template.pug when any Pug file is changed.
I'm guessing I want my plugin to update the ViteDevServer's server.moduleGraph. Is there a supported way to do that?
Huge thanks to the friendly Vite chat on Discord for setting me in the right direction.
The two keys I was missing:
Use Pug compile to create a render method that has render.dependencies, as done by Parcel
Use virtual import statements to attach the dependencies to the transform hook result, as done by vite-plugin-svelte.
Here is the working plugin:
import { compile } from 'pug';
export default function pluginPug() {
return {
name: 'vite-plugin-pug',
transform(src, id) {
if (id.endsWith('.pug')) {
const render = compile(src, { filename: id });
const html = render();
let code = '';
for (let dep of render.dependencies) {
code += `import ${JSON.stringify(dep)};\n`;
}
code += `export default ${JSON.stringify(html)};`;
return { code };
}
},
};
}
I want to make separate files for data and methods, and access them in a third file where I could just display them. There will be a lot of variables and math going on, and keeping everything in a single Vue file makes the code hard to read. That kind of 'data-store' for both variables and functions would help me keep my code clean. Thank you in advance!
One thing I've done in the past is put those files in my assets folder. For example, I have a static set of data in a json file I need in my component. I do the following:
<template>
<div></div>
</template>
<script>
export default {
name: 'FetchData',
data() {
return {
retrievedData: require('../assets/data.json'),
}
},
created() {
this.emitFormattedData(this.retrievedData);
}
methods: {
emitFormattedData(rawData) {
const formattedData = this.formatData(rawData);
this.$emit('fetch-products-event', formattedData);
},
formatData(rawData) {...}
}
}
You could do the same for variables by using exportable functions (I dont think you can export variables).
// helper js file
export function myImportantMathVariable() {
//return some value
}
and in your Vue file
<script>
import {myImportantMathVariable} from '../assets/helper.js';
export default {
name: 'MyAwesomeMathComponent,
data() {
return {
someProp: number
}
},
methods: {
someSuperMethod() {
return 5 + myImportantMathVariable();
}
}
}
...
Running into a problem which is surely related to Webpack.
Tried to do the most basic of services as a smoke test (start small) in a Vue app created by the CLI.
Versions:
Vue CLI: 3.11.0
vue 2.6.10
#vue/CLI-Service 4.0.5
I created a folder called shared inside the src folder of my project. The HelloWorld.vue file is in the components folder. In that file, I imported a data service which I placed inside shared and attempted to use it in the Created event of the HelloWorld component:
<script>
import { dataService } from "../shared";
export default {
name: "HelloWorld",
props: {
msg: String
},
created() {
dataService.addWebSite();
}
};
</script>
The data service is very simple and just meant to hit an API (data.service.js):
import * as axios from 'axios';
const addWebSite = function () {
axios({
method: 'POST',
url: 'https://localhost:44362/WebSites/CreateWebSite',
data: {
name: "Pluralsight",
url: "http://Pluralsight.com"
}
}).then((response) => {
var discard = response.data;
return discard;
});
};
export const dataService = {
addWebSite: addWebSite
};
When I execute npm run serve, I see the following error message:
ERROR Failed to compile with 1 errors 6:13:39 PM
This relative module was not found:
../shared in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/HelloWorld.vue?vue&type=script&lang=js&
I'm guessing this is some kind of Webpack relative path thing, but am at a loss and have not been able to solve it using Google.
The vue.config.js looks like this:
module.exports = {
configureWebpack: {
devtool: 'source-map',
}
};
And I have tried adding a publicPath property of both './' and '/' to that exported object.
Anyone know what's going on?
When you try to import from a folder instead of file, like this
import { dataService } from "../shared";
it implies that you actually want to import from "../shared/index.(any_supported_extension)". But since your file is actually named data.service.js you will have to change your import to
import { dataService } from "../shared/data.service.js";
I am using nuxt.js. I have a helper.js script inside plugins folder which has a simple Test() function. Now how can I can call the Test() method inside pages which is in helper.js file.
helper.js file:
export default function Test() {
return 'This is test'
}
to access your global methods entire application:
1-create ./plugins/helpers.js .
2-edit ./plugins/helpers.js :
import Vue from 'vue'
Vue.mixin({
methods:{
mySpecialMethod(value){
console.log(value)
},
}
})
3-edit ./nuxt.config.js :
plugins: [
...
{ src: '~/plugins/helpers' },
...
],
now you can access your global method by:
this.mySpecialMethod()
Using the inject method
There is actually an easy way to do this by using the 'inject' method.
As described in the docs...
The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use Vue.use(), you should create a file in plugins/ and add its path to plugins in nuxt.config.js.
in your plugin simply use inject like this:
export default ({ app }, inject) => {
inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
and in your components you can use it as follows:
export default {
mounted(){
this.$myInjectedFunction('works in mounted')
},
asyncData(context){
context.app.$myInjectedFunction('works with context')
}
}
"Manual" injection
If you plan on injecting something yourself check out the Vue Docs on Adding Instance properties
There may be data/utilities you’d like to use in many components, but you don’t want to pollute the global scope. In these cases, you can make them available to each Vue instance by defining them on the prototype
Vue.prototype.$appName = 'My App'
And prefix these injected properties with '$'...
$ is a convention Vue uses for properties that are available to all instances. This avoids conflicts with any defined data, computed properties, or methods.
If you just want to use the code in your components (pages), you only need to import and use the method:
TestPage.vue
<template>
<div>
<h1>{{ getTest }}</h1>
</div>
</template>
<script>
import test from '~/plugins/helper.js'
export default {
computed: {
getTest () {
return test()
}
}
}
</script>
Hello you can inject the function globally into Vue doing the following:
./plugins/myPluging.js
import Vue from 'vue'
Vue.prototype.$nameOfMyPlugin = (args) => {
// Code here
}
Them in all your components you can access it this way:
./components/myComponent.vue
<script>
export default {
name: 'c',
mounted () {
this.$nameOfMyPlugin('something useful')
}
}
</script>
And that's it :) hope this helps.
-- Reference: https://nuxtjs.org/guide/plugins/#inject-in-root-amp-context
Below is a a custom js plugin that I have used in one of my nuxt projects.
create your file inside the plugins folder, and make your own function as below
export default (context, inject) => {
const formatDate = (dateTime) => {
if (typeof(dateTime) === 'undefined' || dateTime === null) {
return null;
}
let tempDate = new Date(dateTime);
tempDate.setMinutes(tempDate.getMinutes() -
tempDate.getTimezoneOffset());
tempDate = tempDate.toISOString().slice(0, 16);
return tempDate;
}
// Inject $hello(msg) in Vue, context and store.
inject('formatDate', formatDate)
// For Nuxt <= 2.12, also add 👇
context.$formatDate = formatDate
}
Add the plugin to nuxt.config.js and you will be able to use it globally.
myPlugin.js
export default (_, inject) => {
const myFuncA = value => return value;
const myFuncB = value => return myFuncA(1) + value;
inject('myPlugin', { myFuncA, myFuncB }
)
nuxt.config.js
plugins[
'#/plugin/myPlugin.js'
]
myComponent.vue
created(){
console.log( this.$myPlugin.funcA(2) );
}
in myPlugin.js, instead of "_" can use some public nuxt variables like {$config}