How to bind console.log to "l" in vue.js? - javascript

main.js has this code
window.l = function () { }
try {
window.l = console.log.bind(console)
} catch (e) { }
which works in non-Vue apps. However, when calling
l("test")
from a Vue action/method, it complains it isn't defined.
How can that work?
Reasoning: need to output some debugging data, with as less typing as possible.

When you want to add global-level functionalities to Vue, you should generally use mixins or plugins.
For the next examples, I assume you are using vue-cli with the complete webpack template. Moreover, we will use App.vue as a practical reference, but you can apply the same principles to other components...
Mixins
Create a mixin named log.js (in a mixins folder) with the following code:
export default {
methods: {
l (...args) { // rest parameters
console.log(...args) // spread operator
}
}
}
Open App.vue, import your mixin and use it:
<script>
import log from './mixins/log'
export default {
name: 'app',
mixins: [log],
created () {
this.l('Foo', 'Bar') // Foo Bar
}
}
</script>
Plugins
Create a plugin named log.js (in a plugins folder) with the following code:
export default {
install (Vue, options) {
Vue.prototype.$l = console.log.bind(console)
Vue.l = console.log.bind(console)
}
}
Open your main.js and declare your global plugin:
import log from './plugins/log'
Vue.use(log)
Open App.vue, import Vue and use your plugin:
<script>
import Vue from 'vue'
export default {
name: 'app',
created () {
this.$l('Foo') // Foo
Vue.l('Bar') // Bar
}
}
</script>
You might say: "Hey, why should I have to write this or Vue? I just wanna write l, that's all!". Well... This is actually how Vue has been designed. In order to provide global functionalities (shared by all components), you have to add static properties to the Vue object or prototype properties (Vue.prototype) that are accessible through this in Vue instances.
EDIT
I have just thought about an alternative solution...
You can edit your index.html to add this:
<script>
var l = console.log.bind(console)
</script>
Then, to avoid ESLint errors, you should also edit your .eslintrc.js file to reference your new global variable:
globals: {
l: true
}
The file looks like this:
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
globals: {
l: true
},
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}
Restart your dev server. Now you should be able to use l in your code:
<script>
export default {
name: 'app',
created () {
l('It works!')
}
}
</script>

Assign console.log like this.
window.l=console.log;

Related

How do I access environment variables in Strapi v4?

Strapi Version: 4.3.0
Operating System: Ubuntu 20.04
Database: SQLite
Node Version: 16.16
NPM Version: 8.11.0
Yarn Version: 1.22.19
I have created Preview button for an article collection type. I'm using the Strapi blog template. I managed to make the Preview button appear in the Content Manager. I hard coded the link to be opened when you click the Preview button and it works. Now, I want the plugin to use a link with environment variables instead of a hard coded link. I don't know how I can access the environment variables in the source code for the plugin.
My objective:
I want to replace
href={`http://localhost:3000?secret=abc&slug=${initialData.slug}`}
with
href={${CLIENT_FRONTEND_URL}?secret=${CLIENT_SECRET}&slug=${initialData.slug}`}
in ./src/plugins/previewbtn/admin/src/components/PreviewLink/index.js
where CLIENT_FRONTEND_URL and CLIENT_SECRET are environment variables declared like so in .env:
CLIENT_FRONTEND_URL=http://localhost:3000
CLIENT_PREVIEW_SECRET=abc
Here's a rundown of the code I used:
First, I created a strapi app using the blog template, then created a plugin.
// Create strapi app named backend with a blog template
$ yarn create strapi-app backend --quickstart --template #strapi/template-blog#1.0.0 blog && cd backend
// Create plugin
$ yarn strapi generate
Next, I created a PreviewLink file to provide a link for the Preview button
// ./src/plugins/previewbtn/admin/src/components/PreviewLink/index.js
import React from 'react';
import { useCMEditViewDataManager } from '#strapi/helper-plugin';
import Eye from '#strapi/icons/Eye';
import { LinkButton } from '#strapi/design-system/LinkButton';
const PreviewLink = () => {
const {initialData} = useCMEditViewDataManager();
if (!initialData.slug) {
return null;
}
return (
<LinkButton
size="S"
startIcon={<Eye/>}
style={{width: '100%'}}
href={`http://localhost:3000?secret=abc&slug=${initialData.slug}`}
variant="secondary"
target="_blank"
rel="noopener noreferrer"
title="page preview"
>Preview
</LinkButton>
);
};
export default PreviewLink;
Then I edited this pregenerated file in the bootstrap(app) { ... } section only
// ./src/plugins/previewbtn/admin/src/index.js
import { prefixPluginTranslations } from '#strapi/helper-plugin';
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import Initializer from './components/Initializer';
import PreviewLink from './components/PreviewLink';
import PluginIcon from './components/PluginIcon';
const name = pluginPkg.strapi.name;
export default {
register(app) {
app.addMenuLink({
to: `/plugins/${pluginId}`,
icon: PluginIcon,
intlLabel: {
id: `${pluginId}.plugin.name`,
defaultMessage: name,
},
Component: async () => {
const component = await import(/* webpackChunkName: "[request]" */ './pages/App');
return component;
},
permissions: [
// Uncomment to set the permissions of the plugin here
// {
// action: '', // the action name should be plugin::plugin-name.actionType
// subject: null,
// },
],
});
app.registerPlugin({
id: pluginId,
initializer: Initializer,
isReady: false,
name,
});
},
bootstrap(app) {
app.injectContentManagerComponent('editView', 'right-links', {
name: 'preview-link',
Component: PreviewLink
});
},
async registerTrads({ locales }) {
const importedTrads = await Promise.all(
locales.map(locale => {
return import(
/* webpackChunkName: "translation-[request]" */ `./translations/${locale}.json`
)
.then(({ default: data }) => {
return {
data: prefixPluginTranslations(data, pluginId),
locale,
};
})
.catch(() => {
return {
data: {},
locale,
};
});
})
);
return Promise.resolve(importedTrads);
},
};
And lastly this created this file to enable the plugin Reference
// ./config/plugins.js
module.exports = {
// ...
'preview-btn': {
enabled: true,
resolve: './src/plugins/previewbtn' // path to plugin folder
},
// ...
}
I solved this by adding a custom webpack configuration to enable Strapi's admin frontend to access the environment variables as global variables.
I renamed ./src/admin/webpack.example.config.js to ./src/admin/webpack.config.js. Refer to the v4 code migration: Updating the webpack configuration from the Official Strapi v4 Documentation.
I then inserted the following code, with help from Official webpack docs: DefinePlugin | webpack :
// ./src/admin/webpack.config.js
'use strict';
/* eslint-disable no-unused-vars */
module.exports = (config, webpack) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
config.plugins.push(
new webpack.DefinePlugin({
CLIENT_FRONTEND_URL: JSON.stringify(process.env.CLIENT_FRONTEND_URL),
CLIENT_PREVIEW_SECRET: JSON.stringify(process.env.CLIENT_PREVIEW_SECRET),
})
)
return config;
};
I rebuilt my app afterwards and it worked.
You shouldn't have to change the webpack config just find .env file in the root directory
add
AWS_ACCESS_KEY_ID = your key here
then just import by
accessKeyId: env('AWS_ACCESS_KEY_ID')

How to extend core modules of Vue Storefront

I want to override an action from cart module store. I am trying to extend this CartModule by following this link
Extending and Overriding Modules Doc
I have created a file /src/modules/cart/index.ts with following code
import { VueStorefrontModuleConfig, extendModule, VueStorefrontModule } from '#vue-storefront/core/lib/module'
import { CartModule } from '#vue-storefront/core/modules/cart'
import { cartModule } from './store'
const cartExtend: VueStorefrontModuleConfig = {
key: 'cart',
store: {modules: [{key: 'cart', module: cartModule}]},
afterRegistration: function () {
console.log('Cart module extended')
}
}
extendModule(cartExtend)
export const registerModules: VueStorefrontModule[] = [CartModule]
I am getting error that CarModule type does not match with VueStorefrontModule
Also I don't know what to do next in order to make it effective. Docs are not clear about it. Please help. Thanks
If you want to overwrite action of module you don't want to extend module but store.
Here is example:
Vuestorefront has CartModule (in core) and you need to change code of action refreshTotals.
Code your in file /src/modules/cart/index.ts:
import {StorefrontModule} from '#vue-storefront/core/lib/modules';
import {extendStore} from '#vue-storefront/core/helpers';
const cartModule = {
action: {
async refreshTotals({dispatch}, payload) {
//
// your new (and better!) code ;-)
//
}
},
}
export const MyAwesomeCart: StorefrontModule = function () {
extendStore('cart', cartModule);
}
In last step register this your new module under /src/modules/client.ts:
..
...
import {CartModule} from '#vue-storefront/core/modules/cart';
import {MyAwesomeCart} from "modules/cart/index";
export function registerClientModules() {
registerModule(CartModule); // original module
registerModule(MyAwesomeCart); // your new overwiritng module
...
..

MeteorJS javascript function defined in package is undefined

I have created a custom package in Meteor adding javascript to the application.
My package.js:
Package.describe({
name: 'markel:theme',
version: '1.0.0',
summary: 'Theme package',
});
Package.onUse(function(api) {
// Import all JS files required by the template
api.addFiles(['assets/js/custom.js']);
});
In custom.js:
function theme_test() {
console.log('Theme test');
}
When meteor loads the package in the application, it places the function in IIFE. So the javascript is in (function(){here}). So my function will return undefined.
How can I define that function and use it?
I hope one of these options will solve your issue, as I found it hard to reproduce any undefined values.
Option 1 - Use modules
While you can auto-add files via api.addFiles you can optionally still export them explicitly:
package.js
Package.describe({
summary: 'Theming',
version: '1.0.0',
name: 'marcelweidum:theme',
git: 'https://github.com/MarcelWeidum/stack-question.git'
});
Package.onUse((api) => {
api.use('ecmascript') // required to use import/export
api.addFiles([
'js/custom.js'
], 'client');
api.mainModule('main.js')
});
package/js/custom.js
export const theme_test = function theme_test () {
console.log('Here am I!');
}
console.log('Loaded');
package/main.js (in root folder of the package)
export { theme_test } from './js/custom'
client/main.js
import { theme_test } from 'meteor/marcelweidum:theme'
theme_test()
will give you on the console:
Loaded
Here am I!
Option 2 - use api.export
You can export the theme using an implicit global that is made accessible immediately using api.export:
package.js
Package.describe({
summary: 'Theming',
version: '1.0.0',
name: 'marcelweidum:theme',
git: 'https://github.com/MarcelWeidum/stack-question.git'
});
Package.onUse((api) => {
api.addFiles([
'js/custom.js'
], 'client');
api.export('MyTheme')
});
*package/js/custom.js*
function theme_test () {
console.log('Here am I!');
}
MyTheme = MyTheme || {}
MyTheme.theme_test = theme_test
console.log('Loaded');
*client/main.js*
```javascript
MyTheme.theme_test()
will give you on the console:
Loaded
Here am I!
Option 3 - Import file explicitly
This will hover load the file's content only at the point it's imported
package.js
Package.describe({
summary: 'Theming',
version: '1.0.0',
name: 'marcelweidum:theme',
git: 'https://github.com/MarcelWeidum/stack-question.git'
})
Package.onUse((api) => {
api.use('ecmascript')
})
*js/custom.js* (in root folder of the package)
```javascript
export const theme_test = function theme_test () {
console.log('Here am I!');
}
console.log('Loaded');
package/js/custom.js
export const theme_test = function theme_test () {
console.log('Here am I!');
}
console.log('Loaded');
client/main.js
import { theme_test } from 'meteor/marcelweidum:theme/js/custom'
theme_test()
will give you on the console:
Loaded
Here am I!
Option 4 use bare option, in case the file is used by a compiler plugin:
If you don't want the file to be wrapped inside a closure, for example because it will be used by a custom compier plugin, then add the bare option:
Package.describe({
summary: 'Theming',
version: '1.0.0',
name: 'marcelweidum:theme',
git: 'https://github.com/MarcelWeidum/stack-question.git'
});
Package.onUse((api) => {
api.addFiles([
'js/custom.js'
], 'client', { bare: true });
});
This will still load the file but you will have to use your isobuild plugin to handle the file.

Sapper. How to globally use third-party libraries

I want to access a variable gun in server and client side.
This is my module:
import Gun from 'gun/gun'
import Sea from 'gun/sea' // eslint-disable-line no-unused-vars
export const gun = Gun({
localStorage: true,
radisk: true,
peers: ['http://localhost:8765/gun']
})
If it was a Nuxt, which I want to abandon in favor of a Sapper, I would have implemented it like this:
import Gun from 'gun/gun'
import 'gun/sea'
import 'gun/lib/open'
const gun = Gun({
localStorage: true,
radisk: true,
peers: ['http://localhost:8765/gun']
})
export default ({ app }, inject) => {
inject('gun', () => gun)
}
// nuxt.config.js
...
plugins: [{ src: '#/plugins/gun.js' }]
...
Thus, I would get access to the $gun everywhere:
On the server side:
export default {
asyncData(context){
context.app.$gun()
}
}
And on the client side:
methods: {
submit() {
const gun = this.$gun()
const user = this.$gun().user()
...
}
}
And also in the template:
<template>
<div>{{ $gun }}</div>
</tempalte>
This question does not concern the use of the specific library that is being discussed in the question (gun). It can be a Websocet connection (then we would pass the ws variable sun in the same way.), or an rpc (to connect with Bitcoin) - I can give many examples where this can be important.
Somewhere I read that you need to implement this through the rollbar, somewhere I read about a regular module (es6 or .svelte) - but then I encounter a number of other problems ...
I don't really see the direct question, but I'll just guess... you're trying to use a global variable in svelte (moving from nuxt)?
Svelte uses rollup, and you should have a .rollup.config.js file in your root.
export default {
...
plugins: [
svelte({
// magic happens here
})
]
}
More documentation on (what I think your issue is) including globals.
https://svelte.dev/docs#Compile_time
&
https://github.com/rollup/rollup-plugin-svelte

Vue.js exclude settings file from being bundled

I am using the vue-webpack template and I have created a settings.json file to store environment variables that should be changed when installing the script.
My settings.json (just store the absolute path to the API server):
{
"apiURL": "//localhost/app/server/API"
}
How can I keep the file from being minified/bundled in the production version such that I can change it and the updated file will be used next time the app is accessed (without having to build it again) ?
In my app I use this file via require:
const SETTINGS = require('../settings.json');
I understand that by requireing it webpack will bundle it as a module, but how can I include it in my app such that the settings file will still be a separated file in the production build that I can edit.
Is there a better format/way to store those settings (so that they can be edited in production without re-building) ?
You can define those settings in an object that can be referenced in the externals configuration in webpack.config.js.
The externals configuration option provides a way of excluding
dependencies from the output bundles. Instead, the created bundle
relies on that dependency to be present in the consumer's environment.
Example:
externals: {
appSettings: "appSettings",
"window.appSettings": "appSettings"
}
Where appSettings is a global variable containing the environment variables you want to manipulate.
Alternatively, if you do not like that method that exposes the settings in the global object, you can do the following:
Export a variable with the default settings, which will be included in webpack bundle.
export var appSettings = {
currentSettings: "",
settings: {},
getString: function(strName) {
var sett = this.currentSettings ?
this.settings[this.currentSettings] :
appDefaultStrings;
if (!sett || !sett[strName]) sett = appDefaultStrings;
return sett[strName];
},
getSettings: function() { //Gets all available settings
var res = [];
res.push("");
for (var key in this.settings) {
res.push(key);
}
res.sort();
return res;
}
};
export var appDefaultStrings = {
apiURL: "//localhost/app/server/API"
//...
}
appSettings.settings["default"] = appDefaultStrings;
You can then require or import this variable and use it like so:
import appSettings from "../path/to/appSettings";
appSettings.getString("apiURL"); //"//localhost/app/server/API"
Now that you have your default settings up and running, we will create another file containing the custom settings.
import appSettings from "../path/to/appSettings";
export var appProductionSettings = {
apiUrl: "http://example.com"
//...
}
appSettings.settings["production"] = appProductionSettings;
The last thing you need to do is handle which settings you want to use. I have not used vue.js yet, but hopefully this will lead you in the right direction:
import appSettings from "../path/to/appSettings";
export class MyApp {
constructor() {
this.settingsValue = "";
}
get settings() {
return this.settingsValue;
}
set settings(value) {
this.settingsValue = value;
appSettings.currentSettings = value;
}
}
Change the settings:
import "../path/to/productionSettings";
var app = new MyApp();
app.settings = "production";
With this method you can create and use as many settings files as you want.

Categories

Resources