I'm trying to setup TypeScript HTML app in visual studio. I want to use reactjs v0.14.7
I would like to avoid using tools like Browserify.
However, how to use the react-dom module then?
Let's forget about typescript for a while. I need to get pure ES5 up and running first.
currently, I have this:
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var Button = React.createClass({
render: function () {
return (React.createElement("div", { className: "btn btn-default" }, 'hello world'));
}
});
ReactDOM.render(React.createElement('Button'), document.getElementById('container'));
</script>
however, browser complains, ReactDOM object does not exists.
I have tried:
<script src="Scripts/require.js"></script>
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var React = require('react');
var ReactDOM = require('react-dom');
....
</script>
however, it does not work with require.js: Module name "react" has not been loaded yet for context: _. Use require([])
Can someone bring a little more light into this, please? How to use react without any server side tools like bundling, transpiling etc.
Answers like "use npm" won't be accepted as answer.
RequireJS and require are very different things - more on that later.
If you want to use React without a tool like Browserify or Webpack, then you don't necessarily need a module loader. The hosted versions of React and ReactDOM will expose global variables that you can use out of the box.
<script src="https://fb.me/react-0.14.7.js"></script>
<script src="https://fb.me/react-dom-0.14.7.js"></script>
<script>
console.log(React, ReactDOM);
</script>
Just download these files if you want to work with them locally.
SystemJS
All of that out the way, it sounds like SystemJS and JSPM might be exactly what you're looking for.
First use jspm to install your packages.
jspm install systemjs react react-dom
Then link and configure SystemJS.
<script src='jspm_packages/system.js'></script>
<script>
System.import('app.js');
</script>
Now inside app.js you can write CommonJS style code.
var React = require('react');
var ReactDOM = require('react-dom');
SystemJS will handle the loading of the rest of your scripts. If you want to make a production build, then it's as simple as running jspm bundle app.
CommonJS
The calls to require that you're seeing in the React tutorials and other examples are for a module format called CommonJS.
You use require('react') to get a reference to the value exported by the React module (installed into node_modules with npm). This means you need a pre-browser build step like Browserify or Webpack, that can staple all of the modules you need together and output one big script file.
RequireJS
Confusingly, CommonJS and RequireJS use a function with the same name to specify dependencies. You're trying to use the RequireJS require function as though you were working with CommonJS modules.
If you want to import React with RequireJS instead, then you need to something like this:
<script src="js/require.js"></script>
<script>
require.config({
'baseUrl' : 'Scripts/',
});
require(["react-0.14.7", "react-dom-0.14.7"],
function(React, ReactDOM) {
console.log(React, ReactDOM);
});
</script>
When your code executes, RequireJS will go off and add script tags for the modules you've specified. Then once these scripts have loaded, it will pass the values that they export into the callback function for you to use.
Take a look at this project
https://github.com/ORESoftware/hr4r2
it is doing what you want to do - it is using RequireJS + React + TypeScript. And it is doing serverside rendering and is a SPA.
This project is not using Webpack or Babel.
Here is an example by Dan Abramov himself, the creator of Redux in which he makes a react app without using webpack, babel or browserify.
http://codepen.io/gaearon/pen/ZpvBNJ?editors=0010
In your HTML file inside your body tag write
<div id="root">
<!-- This div's content will be managed by React. -->
</div>
And In your script tag type this
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
PS Make Sure You Include These 2 Libraries At Top
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js
Hope it helps.
Related
I have imported react dev to a webpage (legacy HTML+JQuery) as follows:
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
<script type="module" src="dist/Menu.js"></script>
and I'm trying to use the Menu component, which has the following code:
import menuData from "./menuData";
import MenuItem from "./MenuItem";
export const Menu = () => {
return (
<p>Some code..</p>
)
};
let domContainer = document.querySelector('#main_menu');
ReactDOM.render(<Menu />, domContainer);
In my legacy app, before importing I had to transpile the JSX to JS using:
npx babel --watch src --out-dir dist --presets react-app/prod,
And in my legacy app, in addition to the imports (above), I wrote the following element:
<div id="main_menu"></div>
but my legacy app shows an 404 Error for my imports:
404 https://mywebpage.com/dist/menuData
404 https://mywebpage.com/dist/MenuItem
Any idea what I'm missing? How I can start using React components (with imports of another components) in my legacy HTML+JQuery app?
Do the imported paths really exist on your site? Open a browser and go to
https://mywebpage.com/dist/menuData
If they don't resolve to plain .js source code - which it sounds like they don't - they won't work. You probably need to add the file extension, since it sounds like your server isn't doing it:
import menuData from "./menuData.js";
import MenuItem from "./MenuItem.js";
such that going to
https://mywebpage.com/dist/menuData.js
shows you the JS file.
But an even better option you might also consider would be to bundle the code together during a build process, so that only one .js file has to be served to the client. As an app grows larger and larger, if the client has to request 20 or 30 or more modules from your server, that can be a significant performance hit if you aren't using HTTP/2. Consider a module bundler like Webpack. You may be able to turn your HTML into
<script src="dist/bundle.js"></script>
by bundling all of your modules (and React, and any other libraries you happen to be using here) together into a single file.
Background
I'm trying to create a "buildless" JavaScript app, one where I don't need a watch task running to transpile JSX, re-bundle code, etc every time I save any source file.
It works fine with just first-party code, but I'm stuck when I try to import dependencies from npm.
Goal
I want to achieve this kind of workflow:
npm install foo (assume it's an ES module, not CommonJS)
Edit source/index.js and add import { bar } from 'foo'
npm run build. Something (webpack, rollup, a custom script, whatever) runs, and bundles foo and its dependencies into ./build/vendor.js (without anything from source/).
Edit index.html to add <script src="build/vendor.js" type="module"...
I can reload source/index.js in my browser, and bar will be available. I won't have to run npm run build until the next time I add/remove a dependency.
I've gotten webpack to split dependencies into a separate file, but to import from that file in a buildless context, I'd have to import { bar } from './build/vendor.js. At that point webpack will no longer bundle bar, since it's not a relative import.
I've also tried Snowpack, which is closer to what I want conceptually, but I still couldn't configure it to achieve the above workflow.
I could just write a simple script to copy files from node_modules to build/, but I'd like to use a bundled in order to get tree shaking, etc. It's hard to find something that supports this workflow, though.
I figured out how to do this, using Import Maps and Snowpack.
High-Level Explanation
I used Import Maps to translate bare module specifiers like import { v4 } from 'uuid' into a URL. They're currently just a drafted standard, but are supported in Chrome behind an experimental flag, and have a shim.
With that, you can use bare import statements in your code, so that a bundler understands them and can work correctly, do tree-shaking, etc. When the browser parses the import, though, it'll see it as import { v4 } from 'http://example.org/vendor/uuid.js', and download it like a normal ES module.
Once those are setup, you can use any bundler to install the packages, but it needs to be configured to build individual bundles, instead of combining all packages into one. Snowpack does a really good job at this, because it's designed for an unbundled development workflow. It uses esbuild under the hood, which is 10x faster than Webpack, because it avoids unnecessarily re-building packages that haven't changed. It still does tree-shaking, etc.
Implementation - Minimal Example
index.html
<!doctype html>
<!-- either use "defer" or load this polyfill after the scripts below-->
<script defer src="es-module-shims.js"></script>
<script type="importmap-shim">
{
"imports": {
"uuid": "https://example.org/build/uuid.js"
}
}
</script>
<script type="module-shim">
import { v4 } from "uuid";
console.log(v4);
</script>
snowpack.config.js
module.exports = {
packageOptions: {
source: 'remote',
},
};
packageOptions.source = remote tells Snowpack to handle dependencies itself, rather than expecting npm to do it.
Run npx snowpack add {module slug - e.g., 'uuid'} to register a dependency in the snowpack.deps.json file, and install it in the build folder.
package.json
"scripts": {
"build": "snowpack build"
}
Call this script whenever you add/remove/update dependencies. There's no need for a watch script.
Implementation - Full Example
Check out iandunn/no-build-tools-no-problems/f1bb3052. Here's direct links to the the relevant lines:
snowpack.config.js
snowpack.deps.json
package.json
core.php outputs the shim
plugin.php - outputs the import map
passphrase-generator.js - imports the modules. (They're commented out in this example, for reasons outside the scope of this answer, just uncomment them, run the bundle script, and they'll work).
If you are willing to use an online service, the Skypack CDN seems to work nicely for this. For instance I wanted to use the sample-player NPM module and I've chosen to use a bundle-less workflow for my project using only ES6 modules as I'm targeting embedded Chromium latest version so don't need to worry about legacy browser support, so all I needed to do was:
import SamplePlayer from "https://cdn.skypack.dev/sample-player#^0.5.5";
// init() once the page has finished loading.
window.onload = init;
function init() {
console.log('hello sampler', SamplePlayer)
}
and in my html:
<script src="./src/sampler/sampler.js" type="module"></script>
And of course you could just look inside the JS file the CDN generates at the above url and download the generated all-in-one js file it points to, in order to use it offline as well if needed.
I have seen a lot of questions about this on SO and elsewhere, but so far I had no luck.
For a bit of context, I built a SPA website on a Vue project I created with an "old" command. I don't remember which one but it looked like the following:
vue init webpack <my project>
I recently realized that Vue-CLI 3 would be way easier for me to maintain, keep updated and improve for various contextual reasons, so I installed #vue/cli, created a new project and started to copy/paste files from my old project to the new one.
The old project had a build directory with various webpack config files in it, and I needed jQuery set globally for a package I wanted to use, so I added the following to the "base" config of Webpack.
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
However, with the new project, all I have now as config file is babel.config.js and vue.config.js at the project's root, there are no build nor config directory.
I tried to set jQuery globally with the following lines inside my main.js file:
import jQuery from 'jquery'
window.$ = window.jQuery = jQuery
global.$ = global.jQuery = jQuery
But everytime I reload my page, I get the following message:
jQuery is not defined
So, so far, I use the CDN version of jQuery but I don't feel at ease with this solution.
How should I proceed with a Vue-CLI 3 project?
Thank you in advance
You can use Vue plugins. This allows you to add new property to every single component.
In main.js
import Vue from 'vue';
import jQuery from 'jquery';
Vue.use({
install (V) {
V.$jQuery = V.prototype.$jQuery = jQuery
}
})
Then you can use jQuery everywhere in component.
In MyComponent.vue
import Vue from 'vue'
export default {
mounted () {
this.$jQuery('h1').text('Hello World')
Vue.$jQuery('h1').text('Hello World')
}
}
Even another js file.
In util.js
import Vue from 'vue'
Vue.$jQuery('h1').text('Hello World')
You could go on public/index.html and add the script tag to the body with the route to your jquery file or cdn.
If you put it in a jquery folder in public it would look like:
<body>
<div id="app"></div>
<script type="text/javascript" src="/jquery/jquery-3.4.1.min.js"></script>
</body>
I am not sure if that's exactly what you want but it would make it available globally across your project.
If you are using Jquery plugins, you should do this in your main.js:
/*
* If using Jquery plugins they will expect to be available in the global namespace,
* which isn’t the case when you import/require it. So manually assign jquery to
* window. Use require instead of import because the imports are hoisted to the
* top of a file by the compiler, which would break VueJS code.
*/
const $ = require('jquery')
window.jQuery = window.$ = $;
I know it sounds a bit confusing, but let me explain it here:
Right now there's a module that can be imported as CDN only:
<script src='https://www.example.com/example.min.js'></script>
after including it in index.html (or any .html file)
There's a few functions that can use from the module
<script>
$example_function.doSomething(param1,param2);
$example_function.doSomething2();
</script>
Because the module does not available as NPM package and for people like me want to use it in webpack built Vue.js project it's not so straight forward to use this module.
I know there's plenty of ways to workaround but I want it to be simple as I can just import it globally like other npm packages
import Example from 'example'
Vue.use(Example)
then I can call the function in any Vue components, or in my future vue projects.
Is it possible to achieve this?
I'm experimenting with using web components for a project — essentially custom elements powered by attributes, ideally imported by <link rel="import">.
Here's the problem: I can't find conclusive guidance on where to stick any external libraries my component relies on, such as moment.js or even jQuery.
Most component examples I've seen strictly use vanilla JS. When they do use an external library, they often seem to drop them in using Bower or npm and and refer to them explicitly within the component's HTML:
<script type="text/javascript"
src="/bower_components/jquery/dist/jquery.min.js></script>
These days I'm more accustomed to using webpack to bundle dependencies, so this seems a bit odd.
My question: is it considered better form to include each component's library dependencies within the component directory, or have a central node_modules folder at the project level? How does webpack fit into this?
It's better to have a central node_modules folder at the project level. Most people use Webpack to bundle their code with their dependencies. They use require or import their modules for each component.
a.component.js
import React from 'react'
import $ from 'jquery'
b.component.js
import React from 'react'
app.js
import A from 'a.component.js'
import B from 'b.component.js'
Webpack will have one "entry": app.js and compile it output: app.min.js
why?
It's easier to manage (update, delete, add) dependencies with npm.
The browser will load one file instead of multiple external files.
External info:
https://webpack.js.org/concepts/
https://www.quora.com/Why-use-Bower-when-there-is-npm