How to compile require statements? - javascript

I have the following require statements in my .js file which gets transpiled from ES2017, however, the browser still does not recognize these commands (require is not defined). How can I solve this?
this.e = require('../../e.js'),
this.a = require('../../a.js'),
this.cb = require('../../cb.js'),

Transpiling your code is not enough to make it work in a browser. You will need a build system like webpack to bundle your code into one (or multiple) files that you can include in your web app.
For example webpack can first transpile your code using babel and then bundle your whole app into 1 file which will run in the browser without a problem (as it won't have any require anymore).
Another solution you can use is type="module" in your script tag:
<script type="module" src="/my/app.js"></script>
app.js
import a from "../../a.js";
...

Related

Natively import ES module dependencies from npm without bundling/transpiling first-party source

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.

How do I properly load the lit-html module in Electron

I'm trying to use lit-html to save my self some time, but I'm having trouble getting everything set up correctly.
Electron 4.1.1
Node 11.15
As of 5 minutes before posting this, I've run npm install and electron-rebuild, no luck.
I use require() as one would with any other NPM package
var render = require('lit-html').render
var html = require('lit-html').html
console.log(require("lit-html"))
Unfortunately, I'm greeted with this error
In reference to the three lines of code above.
I don't see any problems with my code.
I've tried reinstalling lit-html through NPM to no avail. I would really love to use this library, but first I have to get over this hurdle. If I'm being honest, I don't know if this error is reproducible, but nothing I do seems to fix it. The problem seems to lie with node and the way that imports are handled.
Am I missing something here? Is this a common issue? If so, what can I do to fix it?
You need to transpile lit-html before you can require it
I tested require('lit-html') and I was greeted with this error:
/home/chbphone55/Workspace/test/node_modules/lit-html/lit-html.js:31
import { defaultTemplateProcessor } from './lib/default-template-processor.js';
It clearly states that the error is coming from lit-html/lit-html.js:31 where the line uses ES Module import syntax.
You can transpile it using tools like Babel or similar ones. However, you may want to try using ES Module syntax so you can import lit-html without transpiling it.
Example:
<!-- HTML File -->
<script type="module" src="index.js"></script>
// index.js
import { html } from 'lit-html';
What if you can't use type="module"
If you are unable to use the type="module" method above, you can also use the ESM package.
ESM is a brilliantly simple, babel-less, bundle-less ECMAScript module loader.
Here are a few examples of how to use it:
Using the node require flag (-r) to load esm before everything else
node -r esm index.js
Loading esm in your main file then loading the rest of your code.
// Set options as a parameter, environment variable, or rc file.
require = require('esm')(module/*, options*/)
module.exports = require('./main.js')

How to use Node.js packages within a client-side html document using browserify

I'm unable to use a node.js module on my website with broweserify. The example only shows how to run a javascript file that is separate from the .html file, not how to use the node.js module within the .html file. Seems like a trivial problem, but I'm unable to make it work.
Here's what I've done:
Initialized node.js & installed a package, npm i webtorrent-health as an example
Created require_stuff.js which consists of a single line: var WebtorrentHealth = require('webtorrent-health')
Run browserify: browserify require_stuff.js > bundle.js
Include package in my html document, e.g. <script src='bundle.js'></script>
Use the package somewhere in my document, e.g. like this: <script>webtorrentHealth(magnet).then(foobazbar())</script>
Despite bundle.js executing and seemingly defining webtorrentHealth, the script within the .html document fails with WebtorrentHealth is not defined. What am I doing wrong? How do I make it work? Thank you!
You're very close to what you want to achieve. In fact, your code bundle.js is inaccessible from outside (in your case the browser) due to browserify, but you can expose your module by writing at the end of your file require_stuff.js:
window.WebtorrentHealth = WebtorrentHealth;
Now you can use WebtorrentHealth in your document.

Is there a way to make Webpack 2 ignore require (CommonJS) calls? To not transpile them?

I have code that has
require(...)
can we make Webpack ignore that and not touch it, so that I can use runtime RequireJS from my Webpack bundle?
The reason is because I'd like to have new code in my app compiled with webpack, and allow it to use RequireJS to pull my old code which is already requirejs calls with a bunch of hacks that are way to difficult to port to modern modules. I just want to import them the old way while write new code with Webpack.
How can we do this?
Put your new code inside a folder, and point a webpack to it, or the opposite, put your legacy code in a folder, or rename each legacy file as file.legacy.js and then use Ignore Plugin:
var ignore = new webpack.IgnorePlugin(/legacy.js$/)
module.exports = {
//other options goes here
plugins: [ignore]
}

"Uncaught ReferenceError: require is not defined" with Angular 2/webpack

I am working an HTML template from a graphic design company into my Angular 2 project using node and webpack.
The HTML pulls in various scripts like this:
<script src="js/jquery.icheck.min.js"></script>
<script src="js/waypoints.min.js"></script>
so I am requiring them in my component.ts:
var icheckJs = require('../js/jquery.icheck.min');
var waypointsJs = require('../js/waypoints.min');
There are several other scripts too and some SASS which appears to be working correctly.
webpack is happy and build it all and an 'npm start' is successful too. However, when it reaches the browser, I get this complaint:
Uncaught ReferenceError: require is not defined node_modules/angular2/platform/browser.js:1 Uncaught ReferenceError: require is not defined
which is actually thrown by this line from url.js:
var punycode = require('punycode');
Is this a CommonJs require? I hadn't used this in web development before a few weeks ago so I'm still untangling the various requires from webback, CommonJs et at.
An extract from my webpack.config.js for the .js loader looks like this:
{ test: /\.js$/, loader: 'script' }
How do I work around this error?
WebPack can do this alone. You need to make sure you load the initial chunk first using a script src tag. It will typically be the value of the entry: key in the WebPack config with -bundle appended. If you're not doing explicit chunking, your entry chunk should be both an initial and entry chunk and have the WebPack runtime in it. The WebPack runtime contains and loads the require function before your code runs.
Your components or whatever you're requiring need to be required from the entry file since your scripts will start there. Basically, if you're not explicitly chunking, the entry point JS file is the only one you can include with script src. Everything else needs to be required from it. What you include will typically have bundle in the JS filename. By default, it should be main-bundle.js.
For anyone that is looking for an answer but the above doesn't work:
Short
Add or Replace current target in webpack.config.js to target: 'web'
A bit longer
Webpack has different targets, if you've experimented with this and changed your target to node it will use 'require' to load chuncks.
The best thing is to make your target (or to add) target: 'web' in your webpack.config.js. This is the default target and loads your chuncks in a way the browser can handle.
I eventually found this solution here.
You can do this in one line assumed that you have
the bundle in dist/bundle.js
the source file client code that will render the page in the browser in
client/client.js
webpack && webpack ./client/client.js dist/bundle.js \
&& webpack-dev-server --progress --color
You need to run webpack again since if some sources in the library change you will get the last changes then in the dist/bundle.js package (of course you can add like a grunt file watch task for this). webpack-dev-server will run the server then.

Categories

Resources