Unexpected token < when using reactjs app - html

I have been following a video tutorial which apparently using JSBin to show its code, when I tried out the code locally then it does not work for me. Could someone please help me to figure out what is the issue.
Below is the code
<!DOCTYPE html>
<html>
<head>
<title>Redux basic example</title>
<script src="https://unpkg.com/redux#latest/dist/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.0/react.min.js" type = "text/babel"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.0/react-dom.min.js" type = "text/babel"></script>
</head>
<body>
<div id='root'>
</div>
<script>
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
};
const Counter = ({ value}) => (<div>{value}</div>);
const { createStore } = Redux;
var store = createStore(counter);
const render = () => {
ReactDOM.render(
<Counter value={store.getState()} onIncrement = {
() => store.dispatch({type: 'INCREMENT'})
}
onDecrement = {
() => store.dispatch({type: 'DECREMENT'})
} />,
document.getElementById('root')
);
};
store.subscribe(render);
render();
</script>
</body>
</html>

You are using JSX in your code, which needs to be transpiled into standard javascript before executing it in the browser.
const Counter = ({ value}) => (<div>{value}</div>);
Look into Babel

The browser is complaining about the JSX code. You should transpile it to regular Javascript before including it in your page. There are several ways to do: Webpack, Babel...
Have a look to create-react-app npm package to get started fast: https://github.com/facebookincubator/create-react-app

Related

Please tell me what a unique selector is set on puppeteer, when elements have duplicate query selector

My Html code has Button-tags that have same id "hoge".
If you get the selector from the Chrome Dev Tool, it will be the same for both "#hoge".
<html>
<body>
<button id="hoge">Hoge</button>
<div class="shadow">
#shadow-root (open)
<button id="hoge">Hoge</button>
</div>
</body>
</html>
I want to get element of button-tag in shadow dom with puppeteer.
But, my javascript code gets element of 1st button.
const element = page.waitForSelector("pierce/#hoge");
This is not what I want.
I'm guessing it's because you didn't specify a unique selector, but i don't know what is unique selector for puppeteer.
If you know how to solve this problem, please let me know.
Long story short
I work with puppeteer a lot and wanted this knowlegde to be in my bag. One way to select a shadow Element is by accessing the parent DOM Node's shadowRoot property. The answer is based on this article.
Accessing Shadow Root property
For your html example this does the trick:
const button = document.querySelector('.shadow').shadowRoot.querySelector('#hoge')
waiting
Waiting though is a little more complicated but can be acquired using page.waitForFunction().
Working Sandbox
I wrote this full working sandbox example on how to wait for a certain shadowRoot element.
index.html (located in same directory as app.js)
<html>
<head>
<script>
// attach shadowRoot after 6 seconds for emulating waiting..
setTimeout(() => {
const btn = document.getElementById('hoge')
const container = document.getElementsByClassName('shadow')[0]
const shadowRoot = container.attachShadow({
mode: 'open'
})
shadowRoot.innerHTML = `<button id="hoge" onClick="doStuff()">hoge2</button>`
console.log('attached!.')
}, 6000)
function doStuff() {
alert('shadow button clicked!')
}
</script>
</head>
<body>
<button id="hoge">Hoge</button>
<div class="shadow">
</div>
</body>
</html>
app.js (located in same directory as index.html)
var express = require('express')
var { join } = require('path')
var puppeteer = require('puppeteer')
//utility..
const wait = (seconds) => {
console.log('waiting', seconds, 'seconds')
return new Promise((res, rej) => {
setTimeout(res, seconds * 1000)
})
}
const runPuppeteer = async() => {
const browser = await puppeteer.launch({
defaultViewport: null,
headless: false
})
const page = await browser.newPage()
await page.goto('http://127.0.0.1:5000')
await wait(3)
console.log('page opened..')
// only execute this function within a page context!.
// for example in page.evaluate() OR page.waitForFunction etc.
// don't forget to pass the selector args to the page context function!
const selectShadowElement = (containerSelector, elementSelector) => {
try {
// get the container
const container = document.querySelector(containerSelector)
// Here's the important part, select the shadow by the parentnode of the
// actual shadow root and search within the shadowroot which is like another DOM!,
return container.shadowRoot.querySelector(elementSelector)
} catch (err) {
return null
}
}
console.log('waiting for shadow elemetn now.')
const containerSelector = '.shadow'
const elementSelector = '#hoge'
const result = await page.waitForFunction(selectShadowElement, { timeout: 15 * 1000 }, containerSelector, elementSelector)
if (!result) {
console.error('Shadow element not found..')
return
}
// since waiting succeeded we can get the elemtn now.
const element = await page.evaluateHandle(selectShadowElement, containerSelector, elementSelector)
try {
// click the element.
await element.click()
console.log('clicked')
} catch (err) {
console.log('failed to click..')
}
await wait(10)
}
var app = express()
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'))
})
app.listen(5000, '127.0.0.1', () => {
console.log('listening!')
runPuppeteer()
})
Start example
$ npm i express puppeteer
$ node app.js
Make sure to use headless:false option to see what's happening.
The application does this:
start a small express server only serving index.html on /
open puppeteer after server has started and wait for the shadow root element to appear.
Once it appeared, it gets clicked and an alert() is shown. => success!
Browser Support
Tested with chrome.
Cheers ' ^^

Simulate multiple domains with rollup-plugin-dev

I am trying to setup a dev environment for developing widgets. In the book Third Party JavaScript They describe how to simulate multiple domains by modifying your hosts file and configuring Apache web server to create two virtual hosts. I was wondering if something similar is possible using the rollup-plugin-dev development server which uses the fastify-http-proxy.
Rollup Config:
...
const devPlugin: Plugin = dev({
dirs: ['dev'],
port: 5000,
// How to configure this?
proxy: []
});
...
Basically I want to serve the widget IIFE code from one domain, say widget.dev and a test html file which loads the script code on another domain, say publisher.dev. The HTML page at publisher.dev would have a <script> tag which loads the widget:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Widget Test Page</title>
<link href="/widget.css" rel="stylesheet" type="text/css"/>
<script async src="http://widget.dev"></script>
</head>
<body>
<div id="widget" data-border></div>
<script>
window.widget = {
// widget config...
}
</script>
</body>
</html>
One way to solve this problem for development is to serve up your widget on some port and then create a separate project that will reach out to grab the js files. I created a separate react app that loaded the script files from the port they are served on. So to keep it extremely simple, in my App.js file of the dev host project I did something like this:
App.js
import React, { useState, useEffect } from 'react';
export const loadScript = (src, id, onError) => {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onerror = (e) => onError(e, 'script', 'could not load script');
script.setAttribute('data-id', id);
document.head.appendChild(script);
};
export const loadStyle = (href, id, onError) => {
const link = document.createElement('link');
link.href = href;
link.rel="stylesheet";
link.type="text/css";
link.onerror = (e) => onError(e, 'link', 'could not load style');
link.setAttribute('data-id', id);
document.head.appendChild(link);
};
const App = () => {
// run this effect one time only
useEffect(() => {
loadStyle('http://localhost:5100/myWidget.css', 'widget-style');
loadScript('http://localhost:3001/myWidget.js', 'widget-id');
}, []);
// ...
};
Depending on your use case, there are (probably) better ways to achieve this.

Facebook comment section will only load once [duplicate]

I am adding facebook social plug in to a webpage
when I manually add :
<div class="fb-comments" data-href="http://website.com/z" data-width="700" data-numposts="7" data-colorscheme="light"></div>
it works , however , when javascript code add it , it doesn't
any ideas ?
The JS SDK goes through your document once when it is initialized, to look for such elements to parse into social plugins. If you want it to also parse content that you add to the document later, you need to call FB.XFBML.parse().
https://developers.facebook.com/docs/reference/javascript/FB.XFBML.parse/
That was great #CBroe!
Thank you! It worked in a Nextjs/React project.
As a reference, please, see a custom hook implementing it:
import { useEffect } from 'react';
let FB;
const useFacebook = ({ addTrack }) => {
useEffect(() => {
const facebookScript = document.createElement("script");
facebookScript.id = 'fb-sdk';
facebookScript.async = true;
facebookScript.defer = true;
facebookScript.crossOrigin = "anonymous";
facebookScript.nonce = "5JOEwLPT";
const track = addTrack ? `&appId=${process.env.NEXT_PUBLIC_FACEBOOK_ID}&autoLogAppEvents=1` : '';
facebookScript.src = `https://connect.facebook.net/pt_BR/sdk.js#xfbml=1&version=v10.0${track}`;
document.body.appendChild(facebookScript);
const startScript = document.createElement('script');
const code = `window.fbAsyncInit = function() {
FB.init({
appId : '${process.env.NEXT_PUBLIC_FACEBOOK_ID}',
autoLogAppEvents : ${addTrack},
xfbml : true,
version : 'v10.0'
});
};`;
startScript.appendChild(document.createTextNode(code));
document.body.appendChild(startScript);
if(window.FB) {
window.fbAsyncInit();
}
return () => {
document.body.removeChild(facebookScript);
document.body.removeChild(startScript);
}
}, [addTrack]);
};
export default useFacebook;
Full code Nextjs Facebook SDK comments sample:
https://github.com/cmdaniel/nextjs-facebook-sdk

Uncaught TypeError: Vue.use is not a function

I am relatively new to VueJS, and now I am trying to replace the
<script src="https://cdn.jsdelivr.net/npm/vue#2.6/dist/vue.min.js"></script>
by
<script src="https://unpkg.com/vue#next"></script>
The problem is that previoulsy working code got broken after this change:
<script>
window.addEventListener('load', () => {
const defaultOptions = {
position: 'bottom-center'
}
Vue.use(Toasted, defaultOptions) # The error arises here
});
</script>
I am running into
Uncaught TypeError: Vue.use is not a function
What am I doing wrong here ?
UPDATE:
I am not using webpack for now. Is it possible to do that without webpack ?
#next refers to vue 3 which has different a different syntax, by assuming that Toasted plugin is compatible with vue 3 you should do :
<script>
window.addEventListener('load', () => {
const defaultOptions = {
position: 'bottom-center'
}
Vue.createApp({}).use(Toasted, defaultOptions)
});
</script>

Conditionally-rendering css in html head

I am trying to dynamically add css to my html head using angular js. Here is sample code
<div ng-repeat="stylesheet in stylesheets">
<link href="/myapp/{{stylesheet.href}}" type="{{stylesheet.type}}" rel="stylesheet" media="{{stylesheet.media}}" title="{{stylesheet.title}}" />
</div>
This code works as expected, but when browser loads the page, it tries to fetch css resources with raw angularjs templates and I see "404 not found error" in network tab of firebug.
Eg: request http://localhost:8080/myapp/%7B%7Bstylesheet.href%7D%7D, status 404
When page is completely loaded, it does substitution of template values and loads proper css.
Is there a way to avoid 404 error and make it load css after angularjs processing?
You should use ng-href instead of href.
<link ng-repeat="stylesheet in stylesheets" ng-href="{{stylesheet.href}}" type="{{stylesheet.type}}" rel="stylesheet" />
Example
I made a AngularJS service to use easily the #Artem solution.
It's here on GitHub.
There's a another option using $route.resolve and promises. This will wait until the CSS is actually loaded not only added to the head (after that the browser just starts retrieving the file and depending on CSS size can cause page reflow).
// Routing setup
.config(function ($routeProvider) {
$routeProvider
.when('/home', {
controller: 'homeCtrl',
templateUrl: 'home.tpl.html'
}).when('/users', {
controller: 'usersCtrl',
controllerAs: 'vm',
templateUrl: 'users.tpl.html',
resolve: {
load: ['injectCSS', function (injectCSS) {
return injectCSS.set("users", "users.css");
}]
}
}).otherwise({
// default page
redirectTo: '/home'
});
})
Service implementation
.factory("injectCSS", ['$q', '$http', 'MeasurementsService', function($q, $http, MeasurementsService){
var injectCSS = {};
var createLink = function(id, url) {
var link = document.createElement('link');
link.id = id;
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
return link;
}
var checkLoaded = function (url, deferred, tries) {
for (var i in document.styleSheets) {
var href = document.styleSheets[i].href || "";
if (href.split("/").slice(-1).join() === url) {
deferred.resolve();
return;
}
}
tries++;
setTimeout(function(){checkLoaded(url, deferred, tries);}, 50);
};
injectCSS.set = function(id, url){
var tries = 0,
deferred = $q.defer(),
link;
if(!angular.element('link#' + id).length) {
link = createLink(id, url);
link.onload = deferred.resolve;
angular.element('head').append(link);
}
checkLoaded(url, deferred, tries);
return deferred.promise;
};
return injectCSS;
}])
You could add a timeout using tries if this is something you would like to include.
Check out this post for more details:https://medium.com/angularjs-meetup-south-london/angular-dynamically-injecting-css-file-using-route-resolve-and-promises-7bfcb8ccd05b
I've created a very simple example of how make a conditionaly css addition
<link rel="stylesheet" ng-if="lang_direction == 'rtl'" ng-href="{{lang_direction == 'rtl' ? 'css/rtl.css' : ''}}" >
For anyone wishing to create truly dynamic CSS at runtime with AngularJS this is what I used.
index.html
<head>
<style type="text/css" ng-bind-html="styles"></style>
</head>
cssService
this.$rootScope.myStyles = ".test { color : red; }";
This is just an example, it may be better for you to put the styles into an indexController if you have one and keep it off the $rootScope