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

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.

Related

Building a Webpack 4 Config for SASS (Compilation, Minification in Prod), JS (Concat + Minification), and Multiple Vue Single Page Applications

Trying to setup a webpack setup for my entire resource generation workflow in our app. I don't need any hot reloading, browsersync, etc. Just needs to watch for changes, and rebuild depedent objects when changes are made. File structure looks like this:
(I apologize for the image I seriously looked up other methods to post structure, but nothing was working on the preview, I can post a fiddle-or-codepen with this output in a comment afterwards)
The only areas of note are:
1) Each folder underneath vue-spas each Single-Page Mini App (SPAs) generates it's own output file of the app.
2) All items in constructs underneath js are concat and minified into one output file (/dist/js/main.min.js) but every item underneath js/components/ just renders a minified and mangled version of that file
Lastly, I understand this is probably a difficult question to wrap around, but I have Gulp doing some of it now, and Webpack doing the Vue compilation, just trying to see if it's possible to consolidate into just webpack and let it do the work.
Thanks for any assistance.
There are a few approaches. The simplest would be to add a key for each app in the entry point configuration in your webpack.config.js file.
That would look like this in your webpack.config.js file:
module.exports = {
entry: {
app1: './vue-spa/vue-spa1/app.js',
app2: './vue-spa/vue-spa2/app.js'
// etc
}
};
This will output individual directories in your dist for each with a nicely bundled app file.
By default, if you pass in a production variable to your webpack build command it'll apply all the optimizations you're looking for. If it's lacking out-of-the-box, there's likely a loader that can handle whatever optimization you need.
For Sass, you can add sass-loader to your webpack file:
https://github.com/webpack-contrib/sass-loader
Your devServer can just watch your vue-spa directory recursively for changes.
Another approach is to use lerna -- though that would require additional configuration, and is only necessary in your situation if you're in an enterprise environment where each individual app is being shipped out to a private NPM registry, and require individual semver.

Require in react can't resolve path

I'm trying to use tracking-js library in my project I'm using react but I dont know if I'm doing anything wrong but keep showing that the module is not found, I already check my package.json and the module install. So this is how I require the module:
const tracking = require("tracking");
what am I doing wrong?
For node, including node-based build tools, first make sure that the module is present. Keep in mind that require does not care about the package.json of your app, only about the module files being present.
Check if node_modules/tracking is present.
Make sure the "main" JS file can be found. If there's a node_modules/tracking/package.json file, see if it has a main property and if the file it references exists. If there is no main property, make sure there's an index.js in the root of the module directory.
If all this is fine and you're getting the module not found error at runtime in client-side JavaScript, then your bundling config may be incorrect, and your webpack/browserify/whatever config will have to be scrutinized for bugs.

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

RequireJS tries to load webpack externals

Using Webpack, I'm exporting two distribution files for a project. One with dependencies bundled and one without.
Throughout the application, we use commonjs require('lodash.assign'); includes which webpack understands.
However, I've configured one of our builds to ignore these (for users who already use lodash and have it available).
externals = {
'lodash.assign': 'var _.assign',
'lodash.clonedeep': 'var _.cloneDeep'
};
This works as expected. However, because our libraryTarget is umd we support RequireJS. However, RequireJS still actually thinks these files should be loaded and I'm seeing a ton of errors:
require.min.js:1 GET http://127.0.0.1/_.assign.js req.load
# Uncaught Error: Script error for "_.assign"
It can't figure out where to find script. How can I configure webpack, or even requirejs to ignore these, since they're being mapped by webpack?
By looking at the compiled output, I see the reason requirejs thinks it's supposed to load these files:
define(["_.assign", "_.cloneDeep"], factory);
When I manually modify code to the following, it works:
define(['lodash'], factory);

Is there a way to lazily set the path of a resource with RequireJS?

So, I have an app that is using requireJS. Quite happily. For the most part.
This app makes use of Socket.IO. Socket.IO is being provided by nodejs, and does not run on the same port as the main webserver.
To deal with this, in our main js file, we do something like this:
var hostname = window.location.hostname;
var socketIoPath = "http://" + hostname + ":3000/socket.io/socket.io";
requirejs.config({
baseUrl: "/",
paths: {
app : "scripts/appapp",
"socket.io" : socketIoPath
}
});
More complicated than this, but you get the gist.
Now, in interactive mode, this works swimingly.
The ugliness starts when we try to use r.js to compile this (technically we're using grunt to run r.js, but that's besides the point).
In the config for r.js, we set an empty path for socket.io (to avoid it failing to pull in), and we set our main file as the mainConfigFile.
The compiler yells about this, saying:
Running "requirejs:dist" (requirejs) task
>> Error: Error: The config in mainConfigFile /…/client.js cannot be used because it cannot be evaluated correctly while running in the optimizer. Try only using a config that is also valid JSON, or do not use mainConfigFile and instead copy the config values needed into a build file or command line arguments given to the optimizer.
>> at Function.build.createConfig (/…/r.js:23636:23)
Now, near as I can figure, this is due to the fact that I'm using a variable to set the path for "socket.io". If i take this out, require runs great, but i can't run the raw from a server. If I leave it is, my debug server is happy, but the build breaks.
Is there a way that I can lazily assign the path of "socket.io" at runtime so that it doesn't have to go into the requirejs.config() methos at that point?
Edit: Did some extensive research on this. Here are the results.
Loading from CDN with RequireJS is possible with a build. However, if you're using the smaller Almond loader, it's not possible.
This leaves you with two options:
Use almond along with a local copy of the file in your build.
Use the full require.js loader and try to use a CDN.
Use a <script> tag just for that resource.
I say try for #2 because there are some caveats. You'll need to include require.js in your HTML with the data-main attribute for your built file. But if you do this, require and define will be global functions, allowing users to require any of your internal modules and mess around with them. If you're okay with this, you'll need to follow the "empty: scheme" in your build config (but not in your main config).
But the fact remains that you now have another HTTP request. If you only want one built file, which includes the require.js loader, you'll need to optimize for only one file.
Now, if you want to avoid users being able to require your modules, you'll have to do something like wrap:true in your build. But as far as I can tell, once your module comes down from CDN, if it's AMD, it's going to look for a global define function to register itself with, and that won't exist because it's now wrapped in a closure.
The lesson I took away from all this: inline your resources to your build. It makes sense. You reduce HTTP requests, minify it all and get gzip compression. You don't expose your modules to the world and everything is a lot simpler. If you cache your resources properly you won't even need to worry about it.
But since new versions of socket.io don't like AMD, here's how I did it. Make sure to include the socket.io <script> tag before requirejs. Then create a requirejs module named socket.io with the following contents:
define([], function () {
var io = window.io;
window.io = null;
return io;
});
Set the path like so: 'socket.io': 'core/socket.io' or wherever you want.
And require it as normal! The build works fine this way.
Original answer
Is it possible that you could make use of the path config fallbacks specified in the RequireJS API? Maybe you could save the file locally as a fallback so your build will work.
The socket.io GitHub repository specifies that you can serve the client with the files in the socket.io-client package's dist/ directory.

Categories

Resources