I am new to Vite and want just one simple thing -> to reference a variable in my DOM that I declared in the main.js.
important code from main.js:
let getThis = 'Why does this not work';
important code from index.html:
<body>
<p id="test">not working</p>
<script type="module" src="/main.js"></script>
<script type="module">
document.getElementById('test').innerHTML = getThis;
</script>
Exmple: https://stackblitz.com/edit/vitejs-vite-urotp2?file=main.js,index.html,counter.js&terminal=dev I searched the Internet for 2 Days now:/
First I had a problem using Bootstrap in combination with Vite. I wanted to trigger a Modal via Javascript like in this example: https://stackblitz.com/edit/github-4akyeo?file=src%2Fjs%2Fmain.js,src%2Findex.html
important code from index.html:
<script>
const myModalAlternative = new bootstrap.Modal('#exampleModal');
myModalAlternative.show();
</script>
important code from main.js:
import * as bootstrap from 'bootstrap';
window.bootstrap = bootstrap;
But I always received Uncaught ReferenceError: bootstrap is not defined(look in the console ). I researched and found out that this is because the bootstrap variable is not linked to the window object but this didnĀ“t fix the issue. So I broke it down and realized this is a more general problem. I assume that it has something to do with the bundling of the files and now the variables aren't readable in the <script>.
Is this even possible or am I missing something here? Is this maybe a normal JavaScript scope issue? Thankful for any help.
Thanks to Arnaud from Vite I have solved the problem.
Here is What he told me:
Variables in ESM modules are scoped to the modules, you can only
access them in other modules by exporting them and using import in the
other module, like you did for the counter. More information here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
If you want to bypass this, you can always set something on window
object to make it global, but that should be used only exceptionally
So I researched JS Modules and fixed both problems mentioned above.
Solving the main problem mentioned in the title
I had to export the variable from a file which is imported to my main.js and then import the variable in my .
code from custom.js:
export let getThis = 'Why does this not work';
important code from index.html:
import { getThis } from './custom.js';
see main problem solved
Fixing 'Uncaught ReferenceError: bootstrap is not defined'
I just had to add type="module" to <script> and bootstrap.Modal('#exampleModal'); is working now.
Keep in mind this works only if you first made bootstrap global like:
import * as bootstrap from 'bootstrap';
window.bootstrap = bootstrap; // <- add to window object to bypass the scope and make it global
see bootstrap problem solved - Stackblitz
I hope this helped someone.
I am importing some React modules from CDN (that's not a requirement, I've also tried with a local build, more in the final question about it):
<script crossorigin src="https://unpkg.com/react-onclickoutside#6.9.0/dist/react-onclickoutside.min.js"></script>
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.0/moment.min.js" integrity="sha512-Izh34nqeeR7/nwthfeE0SI3c8uhFSnqxV0sI9TvTcXiFJkMd6fB644O64BRq2P/LA/+7eRvCw4GmLsXksyTHBg==" crossorigin="anonymous"></script>
<script crossorigin src="https://unpkg.com/react-datepicker#3.1.3/dist/react-datepicker.min.js"></script>
Then I have a script to build the React DatePicker component, this is the relevant snippet from it:
HelloWorld.Example=function()
{
var p,setCount,count,p$1,c,myDate,datePicker;
p=React$2.useState(0);
setCount=p[1];
count=p[0];
p$1=React$2.useState(new moment(new Date((c=Date.now(),DateUtil.DatePortion(c)))));
myDate=p$1[0];
datePicker=React$2.createElement(DatePicker.default,{
selected:new moment(new Date()),
onChange:p$1[1]
});
React.set_setCount(setCount);
return React$2.createElement("div",null,datePicker,React$2.createElement("p",null,(Html.textf(function($1)
{
The error that I see from the JS Console is:
react-datepicker.min.js:1 Uncaught TypeError: o is not a function
at Ee (react-datepicker.min.js:1)
when the script call ReactDOM.render.
Is there a way to understand what is o ? Maybe an import missing?
(Edit Well, looking at chrome debugger and comparing it to github, o is isValidDate, i.e. import isValidDate from "date-fns/isValid";, hence the imports from date-fns are not working from CDN )
Is there a way such that - for example - I can locally npm run build the needed module, react-datepicker, and then call the react API from my script as shown above? (a suggestion that I received was configuring my script as entry in webpack, but afaik React doesn't use webpack, though I see it is used in react-datepicker).
From React docs, I can read that
JSX is not a requirement for using React
so something like the above should be doable, in theory.
I've opened a question/issue on github react-datepicker repo (in the context of calling this component from WebSharper.React).
Is there a way such that - for example - I can locally npm run build the needed module, react-datepicker, and then call the react API from my script as shown above?
Yes, there is a well known solution!
Write an index.js as follows
import React from "react";
import DatePicker from 'react-datepicker'
import "react-datepicker/dist/react-datepicker.css";
export {ImportedComponent}
window.MyDatePicker = function MyDatePicker(props) {
console.log("props from window.MyDatePicker", props)
return React.createElement( DatePicker, props );
}
build via npm and copy the static folder from the build of your by npm run build to the SPA folder of your proj
copy
the 3 script tags from the index.html in the build into the index.html template of your proj
and
<div id="root"></div>
(of course you use a different id for your project app and
there will be nothing to render here)
in my case they are (they will be different for you)
<div id="root"></div>
<script>!function(e){function t(t){for(var n,l,p=t[0],f=t[1],i=t[2],c=0,s=[];c<p.length;c++)l=p[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(a&&a(t);s.length;)s.shift()();return u.push.apply(u,i||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,p=1;p<r.length;p++){var f=r[p];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return e}var n={},o={1:0},u=[];function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="/";var p=this.webpackJsonpcontent_npm=this.webpackJsonpcontent_npm||[],f=p.push.bind(p);p.push=t,p=p.slice();for(var i=0;i<p.length;i++)t(p[i]);var a=f;r()}([])</script>
<script src="/static/js/2.a6e4c224.chunk.js"></script>
<script src="/static/js/main.b075c560.chunk.js"></script>
Now go with
datePicker=React$1.createElement(window.MyDatePicker,{
selected:myDate,
onChange:p$1[1],
showTimeSelect: true,
});
in you SPA.js and enjoy any react component like this one from WebSharper.React!
Btw I had to pass a JS date, not a Moment date here in the selected of props, I'm not sure why, anyway, this is not relevant to the problem.
FYI, this is the F# code from WebSharper project
let myDate, setMyDate = WrapReact.UseState (DateTime.Today.JS)
let importDatePicker = JS.Eval("window.MyDatePicker") :?> React.Class
let propDP =
{
selected = myDate
onChange = setMyDate
showTimeSelect = true
}
let datePicker =
React.CreateElement( importDatePicker, propDP)
WrapReact.setCount <- setCount
div [] [
datePicker
p [] [Html.textf "You selected %s date %s time" (myDate.ToDateString()) (myDate.ToTimeString())]
Full open source project shared on github.
I think that the main problem is that WebSharper scripts are not JavaScript modules. In that case it should be immediate to import an external module or make the above SPA.js as the Webpack main entry. In fact it is well known that there are differences between <script type=module> and <script>
Module Script Execute in Strict Mode
Module Script has its Own Scope
Module Script can Import other Javascript Modules
Module Script has this as Undefined
Inline Module Script can have async Attribute
Module Script is Always Deferred
As confirmed by Adam Granicz indeed on WebSharper side:
that should be the way, yes, #Jand42 and others have been working on changing the current output to support modules and a better TS interoperability - this has been on the agenda for years, so closing it would be a good step forward
(In the meantime there are of course alternatives, e.g. flatpickr, which has bindings also for jQuery, instead of react-datepicker or pure React or F# Fable instead of WebSharper.React and so on)
How to include an entire file into my bundle main.js?
ES6 can import/export functions and classes. But what if i want to include the whole content from another file into my bundle main.js? how to do it?
I came across the query on Stackoverflow: Managing jQuery plugin dependency in webpack.
I'm not sure about this question though. Those options given there seem to target injecting implicit globals, configuring this, disabling AMD, to include large dists. I don't think this is what i want.
Let's say i have two files in src directory
1- rough.js
const rgh = "qwerty"
2- index.js
import './rough.js' //something like this
console.log (rgh)
Now what i expect in bundle.js is
const rgh = "query";
console.log(rgh)
I just want all the content inside one of my file to get all transported to index.js for webpack to bundle them
Those options given there seem to target injecting implicit globals,
configuring this, disabling AMD, to include large dists. I don't think
this is what i want.
To understand this you need to understand what webpack is doing for you. Web pack takes a series of Javascript files (and more importantly their contents) and parses these into one file. That's what it does from a file point of view, but if you ignore the file and think about what it does from a code point of view, it takes each one of the imported objects and makes them available to other objects depending upon the rules you define in your code (using import and export). You can think of this from a closure point of view something like this:
if you have some code like:
import a from 'a.js';
export default b(){
console.log(a.test());
}
This will be turned into something like, in one js file:
var a = (function() {
var testStr = "test";
function test(){
return testStr;
}
return {test:test};
})();
var b = (function(a) {
console.log(a.test());
})(a);
So you can see that the file isn't really important. What's important is the scope. b can use a because it is injected into it's scope (In this instance as a IIFE).
In the above example a and b are in the global scope but testStr isn't.
So when your talking about "importing my file", you need to forget about that and think about what objects in that file you want to import how. Any variables "in that file" declared directly var a = ....; are in the global scope. So it sounds like what you want to do is import the objects in that file into the global scope.
you just need to import that file in main.js
like this way
I'm using webpack and I'm using require to pull in some packages. I have two packages: package1.js and package2.js. package1.js simply creates an object with some properties called pkg1. package2 is a javascript file that contains a self executing function that extends package1. E.g.
package2.js:
!function () {
pkg1.prototype.newFunction = function {return "foo"};
}()
I'm trying to require both of these into a new script in the following manner:
require('package1')
require('package2')
When I do this, I get an error:
Uncaught TypeError: pkg1.newFunction is not a function
I think this is because of Javascripts asynchronous loading: require(package2) executes before require('package1'). My evidence for this is that when I do the following I don't get an error:
require('package1')
!function () {
pkg1.prototype.newFunction = function {return "foo"};
}()
However, this is very messy, and I would like to use require. How would I go about making this work?
Edit: Specific Examples
The leaflet-d3 plugin begins with:
(function() {
L.HexbinLayer = L.Class.extend({
...
})()
Hence, at least to my understanding, putting in a require(leaflet-d3-plugin) should cause this script to execute and extend L which is brought in by require('leaflet')
Similarly, d3-hexbin-v0 starts with:
!function(){d3.hexbin=function(){
...
}}()
Again, the way I read this is that this script simply adds a .hexbin method to d3.
Now if I were just writing html, I would just put these different things in various script tags and this just works:
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.hexbin.v0.min.js"></script>
or
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="static/leaflet-d3.min.js" charset="utf-8"></script>
But since I'm using webpack, I should just be able to require and/or import these libraries after I have installed them with npm or if I just copy the .js in these scripts into some directory and then require them from that location. Unfortunately, this does not seem to work unless I copy the .js in these modules directly into whatever script I am writing. This is what I am trying to avoid.
E.g.
import * as d3 from 'd3'; \\I'm using d3 v4 here.
require('/resources/d3-hexbin.min.js')
results in:
Uncaught TypeError: d3.hexbin is not a function
Webpack loades it synchronously but each file have its own scope.
That's why in your statement
import * as d3 from 'd3'; \\I'm using d3 v4 here.
require('/resources/d3-hexbin.min.js')
your second doesn't find d3 variable.
You can solve it by using ProvidePlugin:
webpack.config.js
plugins: [
new webpack.ProvidePlugin({
d3: 'd3'
}),
... //other plugins
This way d3 will be available throughout the application.
Alternative way to achieve it is to use the following:
import * as d3 from 'd3';
window.d3 = d3;
require('./d3.hexbin.v0.min.js')
Hope it helps you!
I just started using Famo.us and wanted to use it as an opportunity to learn typescript at the same time to leverage on its awesomeness. So I did the following
Used yo famous to create the Famo.us project as per the documentation
I was not sure how to include typescript so I created a typeScriptHTML project, copies the .csproj file over and manually edited it. I tried using the NVTS and specified that it should create it from an existing folder but I always got an error saying that the file path was too long. It checked and some of the modules have very long path. Couldn't even delete them and the system was saying the same thing. In the end I discarded the idea and used the typescript html application. It generated no errors.
I added a file app.ts, wrote some sample code in it and it generated the js file as expected.
Now I wanted to translate main.js to main.ts and I'm stuck with the following issues
i. var Engine = require('famous/core/Engine'); gives the error could not find symbol 'require'.
ii. import Engine = require('famous/core/Engine') gives the error: Unable to resolve external module "famous/core/Engine". Changing the path to "../lib/famous/core/Engine" gives a similar error with a different file name.
iii. Created a file Famous.d.ts but I don't think I'm getting it I'm not doing something right
declare module "famous/core/Engine" {
class Engine{
public createContext(): Engine
}
export = Engine
}
In the end, my confusion is how to I translate the sample code to typescript:
/*globals define*/
define(function(require, exports, module) {
'use strict';
///first
var Engine = require('famous/core/Engine');
var DeviceView = require('./DeviceView');
var mainContext = Engine.createContext();
var device;
createDevice();
function createDevice() {
var deviceOptions = {
type: 'iphone',
height: window.innerHeight - 100
};
device = new DeviceView(deviceOptions);
mainContext.add(device);
}
});
Any assistance appreciated.
It turned out to be a lot easier than I thought. One way was to declare the class and export it as a module
declare class Engine{
...
}
export module 'famous/core/Engine'{ export = Engine; }
Manage to get a tiny definition of famous running using this.