Get config value in vue file - vue.js

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.

Related

How to add included Pug files to Vite module graph

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 };
}
},
};
}

How to mock modules in storybook's stories?

I have a Vue component which includes some external modules with complicated logic. For example:
// Component.vue
import Vue from 'vue';
import { externalModule } from '#/path/to/module';
export default {
methods: {
useExternalModule() {
externalModule.doSomethig();
}
}
};
Is it possible to mock the externalModule inside the story?
I'm using Storybook v6.
You can create a __mocks__ folder to put your mock components in. Then in your .storybook/main.js file use this to point webpack to your mock file.
module.exports = {
// your Storybook configuration
webpackFinal: (config) => {
config.resolve.alias['externalModule'] = require.resolve('../__mocks__/externalModule.js');
return config;
},
};
This is covered in the docs under "Mocking imports".
However, this is a global configuration and not a story level configuration.

Can't import .obj files into my Nuxt components

in my Nuxt project I have a background scene made with Three.js.
Now I want to load an .obj into this scene. So the model has to loaded via the component.
my index.vue component:
export default {
name: 'scene',
data () {
return {
}
},
mounted () {
if(!this.scene) this.scene = new Scene({
$canvas: this.$refs.canvas,
});
}
}
In my .js file(Inside the components, where the .vue is as well):
import * as THREE from "three";
import Common from "../Common";
import { OBJLoader2 } from '~/node_modules/three/examples/jsm/loaders/OBJLoader2.js';
const Model = require('#/assets/models/background_1.obj')
export default class Model_1{
constructor(){
this.init();
}
init(){
var loader = new OBJLoader2();
console.log(Model)
loader.load(Model, (root) => {
Common.scene.add(root);
});
}
}
The Nuxt config:
export default {
mode: 'universal',
build: {
vendor: ['hammerjs'],
extend (config, ctx) {
config.module.rules.push(
{
test: /\.(obj|gltf)$/i,
loader: 'file-loader',
}
);
}
}
}
Following error appears:
Cannot find module '#/assets/models/background_1.obj'
I though that the .vue component will look into the assets folder, gets the obj and just reflects the url. But it's looking for a module, which I don't really understand 🤷‍♂️
The .obj file is located in the assets/models folder.
Ok, although every doc said that if the file is in static/file you'll have to use the src static/file. Now that did not work for me, but just using file as source worked. It's working, but can someone please clarify this since I've been on this problem since 2 days and many migraines 😐
Transfer the file to static folder example static/images/background.png
Then omit the #/assets/
var textureURL = "images/background.png";
var texture = textureLoader.load(textureURL);

Vue Relative Paths with the CLI Service

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";

Vue.js or Nuxt.js centralized app configuration

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.