I'm trying to learn redux and I've run into an error. I only have two files, an index.html file and a main.js file, there are links to the jquery and redux cdns in the html file. I've only gotten to 2.3 in the redux tutorial(http://redux.js.org/docs/basics/Store.html) and am stuck. I have
import {createStore} from 'redux';
at the top of my main.js file, but when I load the application, I get an error pointing to line above saying
SyntaxError: import declarations may only appear at top level
What is a 'top level import declaration'?
Here is a gist to my code if that helps. https://gist.github.com/austincarvey/6e6c8fdc2640b0f9bbfb
The import directive is not recognised by web browsers. It's used at the compilation stage, to tie together different source files and third party modules into a single web bundle. If that doesn't make sense, then I highly recommended learning Babel and either Webpack or Browserify. Babel transpiles ES6 and React syntax to browser friendly ES5 code, whilst Webpack/Browserify bundle your modules.
For now however, if you just want to get on with learning Redux, you can simply remove the import statement and instead use the global variable Redux exposed by the redux CDN script in your gist. i.e.
var store = Redux.createStore(counterReducer);
import is used when you are including a file via es6 modules in a context that supports them (Browserify/Webpack/etc, future versions of browsers).
Since you are including the Redux lib via <script> tag, that takes care of including Redux in the global scope.
In the case of your gist, if you erase line one and change the createStore invocation to Redux.createStore on 29, everything should work.
Related
Does any build tool support this loading strategy, such as webpack or rollup.js.
Build every dependency to a single bundle, and when loading these dependencies, firstly search it in window['package'], if exist, use it. Otherwise dynamic load dependencies bundle to use.
Such app dependency is React, ReactDOM and UiLib.
The built result is:
React -> a.js
ReactDOM -> b.js
UiLib -> c.js
my code -> d.js
if window.React exist but window.ReactDOM and window.UiLib does not exist. d.js should dynamically load b.js and c.js and use window.React.
I know I can config React to externals, but this is a microapp used in many different apps, I'm not sure which packages exist in every global.
Nope. It is not possible directly. For a bundler, it is a binary choice between bundle or not to bundle.
Why? When a bundler encounters a library via import statements like - import React from 'react', it needs to know what global object it should substitute whenever it encounters react package across the entire application dependency graph. This must happen at compile-time. Additionally, loading a library with dynamic decision at runtime means you are introducing an asynchronous behavior in your code which your components or application cannot handle readily.
There are two form factors - a library and application. As far as library is considered, this is the only way to teach bundler (either bundle it or leave it via externals).
At an application level, you can write your own code to partially achieve what you seek with help of CDN. For this, you use externals and tell Webpack, for example, that react will be available as global React object on window namespace.
Now before your library is getting consumed, you have to add a dynamic code where to check for presence of React object.
function async initialize() {
if (!window.React) {
const React = await import(/* webpackIgnore: true */ 'https://unpkg.com/react#18/umd/react.development.js')
window.React = React;
initializeMicroapp();
} else {
initializeMicroapp();
return Promise.resolve();
}
}
Your initialize function for microapp is async and returns a promise. This is usually the pattern to go ahead with shell + micro-frontends.
On a side note, you can use module federation approach which is actually meant to solve exactly similar use-case. With module federation, you can teach Webpack that if the host/shell provides a library, then Webpack should simply ignore its bundled copy of that library while serving only other necessary code. However, I advice caution as it is a very specific pattern and neither de-facto nor de-jure at this point. It is recommended when you are having sufficient scale and many independent teams working on same product space.
I need to assimilate some code into a React app. Problem is, that the code i want to use comes from some example i found on the web, which uses "normal" tags to import various other scripts, via an HTML file.
The main script file that i want to use calls countless various functions from external scripts.(The script "assumes" those functions are available). This of course works in the browser, but not in a build system like Babel/Webpack.
To make things short: what would be the node/es6 equivalent of:
<script src="/dev/getHTMLMediaElement.js"></script>
And how do i make those functions available anywhere in the React app?
My React app is a fairly standard one, booted with react-create-app.
You can require or import this file directly after adding externals option in webpack config
Ref: https://webpack.js.org/configuration/externals/
Does ReactJS reuse imported packages?
Let's say I have a file called DisplayItems.js and EditItem.js. They are both imported into App.js.
If I import a package (like axios) at the top of my DisplayItem.js file (import axios from 'axios';), and I also import it in my EditItem.js file, does my Application grow by 13kb or 26kb (assuming axios is 13kb)?
This behavior is controlled not by React, but by whatever build tool compiles and bundles your import statements into a JavaScript file for the browser.
The Create React App template currently uses Webpack as its build tool. Webpack avoids duplicating code that is imported multiple times; it only writes the definitions once. If you are using a different project setup for your React app, your project may use a different build tool.
In response to jhpratt, I did think of testing it on my own, but I knew it would take some time (about 34 mins).
Here's the test results.
Importing jQuery
2742120 (the control) - with jquery imported once
2742353 - with jquery imported twice (233 byte difference, .2kb)
2741887 - with jquery not being imported (233 byte difference, .2kb)
Importing modal-vanilla
2742120 (the control) - with modal-vanilla being imported once
2742406 - with modal-vanilla being import twice (286 byte difference, .3kb)
2712501 - with modal-vanilla not being imported (29386 byte difference, 29.3kb)
I'm not sure what was going on with jQuery (maybe I added it somewhere else in my project?), but it does look like packages are reused (at least in this instance).
Just in case anyone's wondering, I am using Laravel's React setup.
I've used multiple 3rd party libraries in my ReactJS project like lodash, d3 etc. I just found out that I've not written explicit imports
like
import d3 from 'd3'
or import _ from 'lodash'
in all my components (I've imported them in some though). Yet it all works fine and I can also get the d3 object and _ in the browser console. How is it supposed to be?
Considering this is okay behavior can I just import the node_modules dependencies for react only once in my App(Root) Component and don't import them at all in all the other child components.
P.S I'm using webpack 1 and I've verified the behavior.
Even when it works, it is a bad practice, so my advice would be to play nice and always explicitly import modules you are using.
The reason why it is working is probably because some of those modules declare globals when they are imported, so your components that do not import them still reach global.
I'm trying to use import and export to create modules and it's not working.
I added https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js to the index.html header and tried to import a js file and get an error message saying SyntaxError: import declarations may only appear at top level of a module. What can I possibly be doing wrong?
I know I can use require.js but rather use import and export.
HTML
script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script
JS File
import Mymodule from './modules/mymodule';
Babel cannot perform client-side transpiling of modules, or rather it is not universally supported by browsers. In fact, unless you use a plugin, Babel will transform import into require().
If I run the following code:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<script defer type="text/babel" data-presets="es2015">
import Mymod from './modules/module';
Mymod();
</script>
</head>
I get the following error:
Uncaught ReferenceError: require is not defined
From Babel Docs:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
Most people choose a pre-compiled module bundler like Webpack or Rollup.
If you really want to perform this client-side, use RequireJS with Babel run via a plugin, though you may need to use AMD syntax.
Native browser support for ES6 modules is still in early stages. But to my knowledge there isn't a preset/plugin available yet for Babel to tell it not to transform import/export statements.
The scripts that babel-standalone translates execute by default in global scope, so any symbols defined by them are automatically available to every other module. From that perspective, you don't need import/export statements in your modules.
However, you might be trying to maintain source files that can be used both by babel-standalone (e.g. for quick test environments, feature demonstrations, etc) and via bundlers such as webpack. In that case, you need to keep the import and export statements there for compatibility.
One way to make it work is to add extra symbols into the global scope that cause the import and export code that babel generates to have no effect (rather than causing an error as usually occurs). For example, export statements are compiled into code that looks like this:
Object.defineProperty (exports, "__esModule", {
value: true
});
exports.default = MyDefaultExportedClass;
This fails if there is no existing object called "exports". So give it one: I just give it a copy of the window object so anything interesting that gets defined is still accessible:
<script>
// this must run before any babel-compiled modules, so should probably
// be the first script in your page
window.exports = window;
import statements are translated to calls to require(). The result (or properties extracted from it) is assigned to the variable used as the identifier in the import statement. There's a little bit of complication around default imports, which are different depending on whether or not the result of require() contains the property __esModule. If it doesn't, things are easier (but then you can't support having both default and named exports in the same module ... if you need to do this, look at the code babel produces and figure out how to make it work).
So, we need a working version of require(). We can provide one by giving a static translation of module name to exported symbol/symbols. For example, in a demo page for a React component, I have the following implementation:
function require (module) {
if (module === "react") return React;
if (module === "react-dom") return ReactDOM;
}
For a module returning multiple symbols, you'd just return an object containing the symbols as properties.
This way, a statement like
`import React from "react";`
translates to code that is effectively:
`React = React;`
which is roughly what we want.