imported variable is somehow being accessed before initialization - javascript

This is how my code looks
index.html:
<canvas></canvas>
main.js:
import Class from "./module.js"
export const canvas = document.querySelector("canvas")
const obj = new Class(args)
module.js:
import { canvas } from "./main.js"
const c = canvas.getContext("2d")
export default class Class{
// code
}
This is the error: Uncaught ReferenceError: Cannot access 'canvas' before initialization (in module.js)
What am I doing wrong?
tried with import function and some other stuff but that's not really efficient.

You can move the canvas declaration to another file that the other two modules import.
canvas.js:
export const canvas = document.querySelector("canvas")
Then, main.js and module.js can import it like so:
import { canvas } from "./canvas.js"

Related

Loop Javascript Imports to load into VuexORM

Anytime I have a long list of items to import in javascript my natural intention is to export those items in a separate file, require that file in my main javascript file, then if they need to be loaded into Vue or some other process, loop through them and load them dynamically.
I'm just getting started with VueORM, and ORM Models need to be loaded into the VueORM instance like so:
import Foo from '#/models/foo'
import Bar from '#/models/bar'
database.register(Foo)
database.register(Bar)
My app will have dozens of models so I'd like to export those from a single file as I mentioned, then loop through them and register them.
// main.js
import * as models from '#/models'
Object.keys(models).forEach(key => {
database.register(model[key])
})
In my models I'm exporting each as a function like so:
// models/index.js
export const Foo = () => import('#models/foo')
export const Bar = () => import('#models/bar')
This normally works fine, but in VuexORM the models are not being loaded.
Can someone please advise on a better method to load these Models from a separate file?
Vuex ORM does not handle dynamic imports. Rather than export them as dynamic imports, simply export them using the ordinary ESM syntax?
The following assumes your models are default exports.
// models/index.js
export { default as Foo } from '#/models/foo'
export { default as Bar } from '#/models/bar'
Subsequently, your main.js can aggregate the modules:
// main.js
import * as models from '#/models'
Object.values(models).forEach(model => database.register(model))
If you have Vite you can now do this. Taken from Quasar app.
//store/OrmModelPlugin.js
import { Database, install } from '#vuex-orm/core'
export default function () {
//Require all js files in our models directory
const database = new Database()
const modelFileContext = import.meta.globEager('src/models/*.js')
Object.values(modelFileContext).forEach(modelImport => {
const model = modelImport.default
database.register(model)
})
return install(database)
}
//store/index.js
import { store } from 'quasar/wrappers'
import { createStore } from 'vuex'
import OrmModelPlugin from './OrmModelPlugin'
export default store(function () {
const Store = createStore({
plugins: [OrmModelPlugin()],
})
return Store
})

How can I dynamically export components in index.js?

I'm working on a project with nuxt.js and I want to implement the atomic design methodology
so I currently import the components like this
import ButtonStyled from '#/components/atoms/ButtonStyled.vue'
import TextLead from '#/components/atoms/TextLead.vue'
import InputSearch from '#/components/atoms/InputSearch.vue'
but I need to import like this
import {
ButtonStyled,
TextLead,
InputSearch
} from '#/components/atoms'
the closer I got was that,
/atoms/index.js
const req = require.context('./', true, /\.vue$/)
const modules = {}
req.keys().forEach(fileName => {
const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, '$1')
modules[componentName] = req(fileName).default
})
export const { ButtonStyled, TextLead } = modules
but I'm still defining the export variable names statically, I need to define dynamics based on the components inside the folder
NOTE: I can not use
export default modules
if I use the above code snippet I will not be able to import the way I need it, which is:
import { ButtonStyled } from "#/components/atoms"
require.context is a quite obscure function in Webpack, you will have issues while running unit tests. But, to solve your problem; You will need to import the index.js file in the main.js of your project.
This is how I do it:
_globals.js
// Globally register all base components prefixed with _base for convenience, because they
// will be used very frequently. Components are registered using the
// PascalCased version of their file name.
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context('.', true, /_base-[\w-]+\.vue$/)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\/_base/, '').replace(/\.\w+$/, ''))
)
Vue.component(componentName, componentConfig.default || componentConfig)
})
components/index.js
//...
import './_globals'
//...
main.js
//...
import './components' // This imports in the index.js
//...
This way your components loaded in with require.context() gets registered as a vue component and made globally available. I advice to only use global components with components that will be used a lot. Do not load a component globally if you intend to use it only one time.
You can find a working example here -> https://github.com/IlyasDeckers/vuetiful/tree/master/src
To get your unit tests working with jest, you will need to mock require.context(). This was a true pain, but can be achieved easily by using babel-plugin-transform-require-context
I try to use your way to do that, and known you have make a mistake at module.exports
module.exports can not use import , i think you may can do like this
at atoms/index.js
const req = require.context("./", true, /\.vue$/);
const atoms = {};
req.keys().forEach(fileName => {
const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, "$1");
atoms[componentName] = req(fileName).default;
});
export default atoms;
at where to use
import k from "#/components/atoms/index.js";
export default {
components: {
test1: k.test1,
test2: k.test2
}
};
or index.js
import test1 from "./test1.vue";
import test2 from "./test2.vue";
export { test1, test2 };
and where to use like this
import {test1,test2} from "#/components/atoms/index.js";
export default {
components: {
test1,
test2
}
};
I created a library that does all this for me, maybe it helps other people.
named-exports

get synatx error from writing javascript destructure with export function

I have a index.ts file for export libary, but I got error message like below, what's wrong overhere?, I thought it should work.
// components
import List from './components/List'
import Item from './components/Item'
// containers
import ListStackConatiner from './containers/ListStackConatiner'
const components = {
List,
Item
}
const containers = {
ListStackConatiner
}
export {
...components,
...containers
}
SyntaxError: /somepath/src/index.ts: Unexpected token (17:2)(line in ...components)
You can't do destructuring inside a named export natively - this answer explains why. Instead, you can use Object.assign:
export default Object.assign({}, components, containers);
You could also destructure into another variable, then just export that:
var exportObj = {
...components,
...containers
};
export default {exportObj};
Use
export = {
...components,
...containers
}
instead.

Passing value from p5 sketch to React (with react-p5-wrapper)

I have a p5 webcam video prediction system working right now. Currently, I'm trying to plug this into a React app to create a fuller web app.
My problem is, the prediction is now only made in my p5 sketch, I want the prediction value to be passed into React's App.js for further constructions. Is there any method of doing so?
I'm using react-p5-wrapper btw.
Here's the sketch.js:
import "react-p5-wrapper/node_modules/p5/lib/addons/p5.dom";
import ml5 from 'ml5';
let mobileNet;
let video;
let label='model loading...';
function sketch (p) {
p.setup = function () {
p.createCanvas(1000, 1000);
//imitialize the webcam stream in a object
video = p.createCapture(p.VIDEO);
//hide the webcam stream
video.hide();
//initialize the mobilenet object with a callback
mobileNet= ml5.imageClassifier('MobileNet',video,ModelLoaded);
};
p.draw = function () {
p.image(video,0,0);
p.textSize(16);
p.fill(255,140,0);
p.text(label,10,450);
};
};
function ModelLoaded()
{
console.log('Model is ready');
//predicting the image
mobileNet.predict(result)
}
//callback function to get the results
function result(err,res)
{
//check for errors
if(err)
{
//log the error if any
console.error(err)
}
else{
//get the label from the json result
label = res[0].className;
//predicting the image again
mobileNet.predict(result)
}
}
export default sketch;
And my App.js currently looks like this:
import React, { Component } from 'react';
// import logo from './logo.svg';
import './App.css';
import sketch from './sketch';
import P5Wrapper from 'react-p5-wrapper';
class App extends Component {
componentDidMount(){
}
render() {
return (
<div className="App">
<P5Wrapper sketch={sketch} />
</div>
);
}
}
export default App;
Any help appreciated!
I gave this a go and came up with a solution. It isn't very elegant but it should do. I made a very simple test project in sketch.js where I try to illustrate two ways accessing the infromation. The things to note are the timesClicked variable and the updateWithProps function.
export let timesClicked = 0;
export default function sketch (p) {
p.setup = function () {
p.createCanvas(300, 300);
};
p.draw = function () {
p.background(0);
p.fill(255);
p.ellipse(p.mouseX, p.mouseY, 100, 100);
};
p.updateWithProps() = function(newProps){
if(newProps.getCoords){
p.sendCoords = newProps.getCoords;
}
}
p.mouseClicked = function() {
p.sendCoords(p.mouseX, p.mouseY);
timesClicked++;
}
};
timesClicked is a variable that can be imported and counts the times the mouse has been clicked. It can be modified from inside the sketch scope and imported from other files.
updateWithProps is a function called from the react-p5-wrapper library whenever the component receives props and can be defined inside the sketch.
With this, your App.js file could be modified like so:
import React, { Component } from 'react';
import P5Wrapper from 'react-p5-wrapper';
import sketch from './sketch';
import {timesClicked} from './sketch';
function getCoords(){
console.log(arguments);
}
class App extends Component {
componentDidMount(){
}
render() {
return (
<div className="App">
<P5Wrapper sketch={sketch} getCoords={getCoords}/>
</div>
);
}
}
export default App;
document.body.onkeyup = function(e){
if(e.keyCode == 32){
console.log(timesClicked);
}
}
When running, every time there is a click, the sketch will execute the getCoords() function in the App.js file and, alternatively, every time the space bar is pressed the timesClicked variable will be accessed from the App.js file. I think you can modify this in order to "send" or "read" the prediction value.
Edited as per Daniel's answer
Update from Julian's previous answer:
As of now (August 2022), p.myCustomRedrawAccordingToNewPropsHandler() has been renamed to p.updateWithProps()
Read more: https://github.com/P5-wrapper/react#props

How to import a function to a Vue component?

I am trying to import a single function to my Vue component. I've created a separated js file for my function:
randomId.js:
exports.randomId = () => //My function ...
In my Vue component, I've imported the Random js:
let randomId = require('../functions/randomId');
randomId();
but Webpack throws an error of "randomId is not a function".
I tried to import the file using import syntax, but the error remains.
import randomId from '../functions/randomId';
Should I use some other methods for importing single functions? I'm relatively new to Webpack and JS6.
Change your function module to properly use ES6 export:
export function randomId() { /*My function ...*/ }
And then use ES6 named import:
import { randomId } from '../functions/randomId';
If you want to use CommonJS, then in the file with your randomId function do the following:
function randomId() {
...
}
module.exports = randomId;
And then the let randomId = require('../functions/randomId'); in your Vue component will work.

Categories