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