Using Babel's `sourceRoot` Doesn't Affect Imports - javascript

Currently I can do:
require('./frontend/src/components/SomeComponent');
But if I set the following in my webpack.config.js:
resolve: {
root: path.resolve('frontend', 'src')
}
I can instead do:
require('components/SomeComponent');
The problem is, when I don't use Webpack (eg. in a test environment) all of my imports break. According to the Babel docs, the sourceRoot property sets the "root from which all sources are relative." This made me think I could add the following to my .babelrc to fix my imports:
"sourceRoot": "frontend/src"
... but no such luck. When I do require('components/SomeComponent'); in babel-node it fails. When I just use Babel to transpile the file, the require line is the same whether or not I set a sourceRoot.
So, my question is, is there any way (with or without sourceRoot) to simulate webpack's resolve.root in Babel?
P.S. I know there are several Babel plug-ins which address this problem, but all of the ones I've seen require you to add a ~ to the require path (which of course breaks imports in Webpack).

Many project have webpack + babel, and in many projects you sometimes bypass webpack (as in your case - for tests).
In such cases, all the resolve aliases should live in babel.
There are plugins out there to allow one reading the configuration of the other (and similar plugins for eslint etc.).

Related

VS Code shows module not found even though WebPack build works

My VS Code says that it can't find an import even though my WebPack build still works.
Here is the import...
import * as tf from '#tensorflow/tfjs';
and the message from VS Code:
Cannot find module '#tensorflow/tfjs'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?
I have read something about path aliases which can be set up in the tsconfig.json to shorten long paths to modules. But if this is a path alias and I don't have it configured in my tsconfig.json, how does WebPack know where the module is located?
I also read that the convention for path aliases is to start with an "#" but the folder in the "node_modules" itself is called "#tensorflow", so i don't know if it really is a path alias and if not, maybe WebPack magically knows that it has to search in "node_modules" for this module?
As you can see i'm really confused about this and i would be greatfull if somebody could clear this up for me and explain what i must do to stop VS Code from complaining about the import.
Found the solution on my own.
I only found stuff about defining the aliases in the tsconfig.json expclicitly in the "path" option, but this couldn't be the answer to my problem because in my other Angular projects there is nothing like this defined even though I'm using #Angular imports there a lot without this problem.
But then I found this in my Angular project "moduleResolution": "node".
As stated in othe typescript documentation:
However, resolution for a non-relative module name is performed differently. Node will look for your modules in special folders named node_modules.
And behold, it works. Yes I could have probably tried this earlier, since its written in the message from VS Code from my question, but i though this was something for only node.js specific projects and I didn't read about this anywhere.

How to find an ES6 import module without a relative path?

I have an ES6 import.
import MyAwesomeComponent from 'packageNameOnlyWithoutPath';
I want to inspect the file packageNameOnlyWithoutPath. But I can't find it. I looked in node_modules but I don't see it there. So it might be hiding out elsewhere in the app.
Is there a canonical way to find the path that leads to packageNameOnlyWithoutPath?
you might want to take a look at index.js file in the packageNameOnlyWithoutPath folder inside the node_modules.
Else use text editors which supports goToDefinition plugin
TL;DR: Check resolve aliases in Webpack (or similar bundler) config or .babelrc
There's two places you can check first.
If you are using a bundler like Webpack, resolve aliases can be declared in the Webpack config file (usually webpack.config.js).
But I have also recently started using pure babel and node. The reoslves can also be declared in the .babelrc file (cleaner approach IMHO).
You should find what you're looking for in one of the above.

Migrating from requirejs to webpack

I'm migrating/moving a project based on require.js to webpack v3. Since all my modules are using the following syntax:
define([modules,..], function(mod1,..)
Which declares which modules to use, and assigns the modules to the variables in the anonymous function. This seems to be deprecated since v2 of webpack. I can't find any information about this (except for the documentation for web pack v1).
Should I rewrite all my modules to the commonjs (including dependencies) or are there any smart way to use the AMD modules?
Help much appreciated :-)
Regards
AMD never found much use outside of requirejs so likely you will need to convert. There are tools that will help:
https://github.com/anodynos/uRequire can convert code from AMD -> UMD / CommonJS
There are caveats from (https://github.com/anodynos/uRequire/wiki/nodejs-Template):
Runtime translation of paths like models/PersonModel to ../../models/PersonModel, depending on where it was called from. You 'll still get build-time translated bundleRelative paths, to their nodejs fileRelative equivalent.
For most projects this is not an issue.
Can't use the asynchronous version of require(['dep'], function(dep){...})
You should be able to use the synchronous version of require. If using webpack2 you can use System.import or require.ensure
Can't run requirejs loader plugins, like text!... or json!...
You will find webpack version of all of these plugins
There's no mapping of /, ie webRootMap etc or using the requirejs.config's {baseUrl:"...."} or {paths:"lib":"../../lib"}
This can be replicated with https://www.npmjs.com/package/babel-plugin-module-alias
The CaptEmulation's answer is not valid for newer Webpack versions. Webpack supports AMD natively (neither additional loaders, nor plugins need to be installed). A thorough instruction is available here: https://webpack.js.org/api/module-methods.
This fact may easily go unnoticed when one tries to rewrite a RequireJS-based build to Webpack, as RequireJS uses relative paths without the trailing ./, e.g.
define('app/dep1', function(dep1) { ... });
which will not pass in Webpack without additional configuration (assuming that both require.config.js and webpack.config.js are in the same directory):
{
resolve: {
modules: [ './', ... ] // other entries possible here
}
}

Why the need for browserify `paths` definition?

The link https://github.com/jhades/angularjs-gulp-example/blob/master/gulpfile.js has the gulp build-js task definition using browserify paths. I don't understand the need for it... wasn't it possible just to specify the entries as entries: './js/**/*.js', and this would have caused it to search all the sub-directories as well... instead of explicitly specifying paths: ['./js/controllers', './js/services', './js/directives'], which are all sub-directories of the same parent?
Any hints appreciated.
The author is using the paths configuration to enable non-relative require calls like these:
require('todoCtrl');
require('todoStorage');
require('todoFocus');
require('todoEscape');
require('footer');
Browserify emulates Node's module resolution mechanism (which is explained here) and when Node resolves a non-relative require, it looks in node_modules. The paths option gives Browserify a list of paths that are not in node_modules that it should check (before checking node_modules) when attempting to resolve non-relative require calls.
If all of your require calls for modules in your own project use relative paths (e.g. require('./js/controllers/todoCtrl')), you won't need the paths configuration option.
Well, one simple answer seems to be the fact that **/* is not recognised by browserify! You would have to require("glob") to do that... but it's probably simpler just to use paths to specify the extra folders.

How can I use babel-polyfill for multiple separated entries / outputs?

I have this in my webpack.config.js to create two different outputs from two sources:
module.exports = {
entry: {
'dist/index.js': ['babel-polyfill', './src/Component.jsx'],
'example/bundle.js': ['babel-polyfill', './src/Page.jsx'],
},
output: {
path: './',
filename: '[name]',
},
...
Compiling it with webpack works just fine, but if I load index.js in a browser I get this error:
Uncaught Error: only one instance of babel-polyfill is allowed
I need babel-polyfill for both outputs. What can I do?
When developing a library (as opposed to an application), the Babel team does not recommend including babel-polyfill in your library. We recommend either:
Assume the ES6 globals are present, thus you'd instruct your library users to load babel-polyfill in their own codebase.
Use babel-runtime by enabling babel-plugin-transform-runtime, which attempts to analyze your code to figure out what ES6 library functionality you are using, then rewrites the code to load the polyfilled logic from babel-runtime instead of from the global scope. One downside of this approach is that it has no way to polyfill new .prototype methods like Array.prototype.find since it can't know if foo.find is an array.
So my recommendation would be to remove babel-polyfill from your dist/index.js bundle entirely.
Use idempotent-babel-polyfill
import 'idempotent-babel-polyfill';
https://github.com/codejamninja/idempotent-babel-polyfill

Categories