How to apply babel loader to `jsnext:main` but not `main`? - javascript

With the jsnext:main property in package.json and tree-shaking, it seems like it would be preferable to use the es6 version and babel-loader to get a smaller build than to always import the whole UMD package from main.
I know not every package supports jsnext:main, but for the ones that do I want to apply babel-loader and cherry-pick imports.
Example of es6 package:
{
"name": "module",
"main": "dist/index.js",
"jsnext:main": "src/index.js"
}
Example of commonjs or UMD dependency:
{
"name": "module",
"main": "lib/index.js"
}
Right now I exclude all node modules in webpack.
{
test: /\.(jsx|js)$/,
exclude: /node_modules/,
loader: "babel-loader"
}
Is there some way to configure the loader to include if there is a jsnext:main and exclude otherwise? This might be overkill but it seems objectively better to use es6 imports when supported.

Related

Webpack uses ESM part of library although it requires CommonJS?

I'm currently having a weird issue:
Uncaught (in promise) ReferenceError: Cannot access 'Agile' before initialization,
which is probably caused by webpack trying to correctly transform the ESM part of my library into CommonJs. Unfortunately, it doesn't do a good job and I end up with the error mentioned above.
My library supports both: CommonJs and ESM. So I'm wondering why webpack uses the ESM part and transforms it into CommonJs, instead of directly using the CommonJs part of my library?!
Why am I so sure that it has something to do with the ESM to CommonJs transformation?
Well, I once forced webpack to use the CommonJs part of my library by removing the ESM support. By doing so, I simply deleted the path to the ESM module in the package.json of my library.
"module": "dist/esm/index.js"
After unsupporting ESM, webpack was forced to use the CommonJs part
and it works as expected, since webpack doesn't have to transform anything anymore. (see image)
ESM transformed to CommonJS [not working]
Untransformed CommonJS [working]
Since my library should support both: ESM and CommonJS,
simply unsupporting ESM is no solution.
Here is the package.json of my library:
{
"name": "#agile-ts/core",
"version": "0.2.0+17b078aa",
"author": "BennoDev",
"license": "MIT",
"homepage": "https://agile-ts.org/",
"description": "Spacy, Simple, Scalable State Management Framework",
"keywords": [
// ..
],
"main": "dist/index.js", // <!-- CommonJs
"module": "dist/esm/index.js", // <!-- ESM
"types": "dist/index.d.ts",
"scripts": {
// ..
},
"dependencies": {
"#agile-ts/utils": "^0.0.8"
},
"peerDependencies": {
"#agile-ts/logger": "^0.0.8"
},
"peerDependenciesMeta": {
"#agile-ts/logger": {
"optional": true
}
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/agile-ts/agile.git"
},
"bugs": {
"url": "https://github.com/agile-ts/agile/issues"
},
"files": [
"dist",
"LICENSE",
"README.md",
"CHANGELOG.md"
],
"sideEffects": false
}
Maybe I've misconfigured something in the package.json
and thus webpack uses ESM although it requires CommonJs?
Node Version: v16.3.0
Github Repo: https://github.com/agile-ts/agile/tree/master/packages/core
Ok, I fixed this issue by resolving all circular dependencies ^^
See: https://github.com/agile-ts/agile/issues/193

Configure a js library to tell webpack to use the ES6 module dist file

I maintain a library that has has a /dist folder with versions for CommonJS, ES6 modules, and direct <script> loading.
The package.json file is configured to identify each version:
"type": "module",
"main": "dist/pretty-print-json.umd.cjs",
"module": "dist/pretty-print-json.esm.js",
"browser": "dist/pretty-print-json.min.js",
When the library is installed:
$ npm install pretty-print-json
and imported:
import { prettyPrintJson } from 'pretty-print-json';
into a project with webpack, IDEs correctly interpret the ES6 module version plus the TypeScript declaration file (dist/pretty-print-json.d.ts).
However, the build process fails:
./src/app/app.component.ts:74:13-35 - Error: export 'prettyPrintJson' (imported
as 'prettyPrintJson') was not found in 'pretty-print-json' (module has no
exports)
The ES6 module version has an export statement:
export { prettyPrintJson };
After a bunch of experiments with a simple Angular project, I figured out that webpack is using the "browser" version instead of the "module" version.
How do you configure a library so that webpack correctly picks up the "module" version without breaking support for the other versions?
The browser field takes priority over module and main if your target is the browser.
I found this solution for your problem:
{
"name": "main-module-browser",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"browser": {
"./dist/index.js": "./dist/index.browser.js",
"./dist/index.esm.js": "./dist/index.browser.esm.js"
}
}

Yarn won't publish/add both ESM and CJS versions of package?

We have an application bundled with Parcel that consumes a UI library (react components). The UI library is bundled with Rollup and published as a private package on NPM.
I've been trying to migrate our application to use Parcel 2, but Parcel complains that it cannot locate the ESM version of the UI library within the dist folder. Sure enough, when I check my node_modules directory, the dist folder for the UI lib includes only one file: index.cjs.js.
The weird part is that the UI lib is set up to build in both CJS and ESM formats with sourcemaps. When I build the project locally, Rollup produces both CJS and ESM files and their sourcemaps: index.cjs.js, index.cjs.js.map, index.esm.js, and index.esm.js.map. So, somehow, it seems that either: (1) Yarn is only publishing the CJS version of the library to NPM or (2) When the UI lib is added to the application, only the CJS version is being built. Neither of those situations makes sense to me.
Here's the relevant sections of our package.json and rollup.config.js files:
{
"name": "#thecb/components",
"version": "4.0.23",
"description": "Common lib for CityBase react components",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"source": "src/index.js",
"scripts": {
"storybook": "start-storybook",
"build": "rollup -cm"
},
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import babel from "rollup-plugin-babel";
import json from "rollup-plugin-json";
import visualizer from "rollup-plugin-visualizer";
import pkg from "./package.json";
import * as formattedInput from "formatted-input";
const globals = {
react: "React",
"react-dom": "ReactDOM"
};
const plugins = [
resolve({ preferBuiltins: false }),
babel({
exclude: "node_modules/**",
presets: ["#babel/env", "#babel/preset-react"]
}),
json(),
commonjs({
include: "node_modules/**",
namedExports: {
"formatted-input": Object.keys(formattedInput)
}
}),
visualizer()
];
const external = [...Object.keys(pkg.peerDependencies || {})];
const output_data = [
{
file: pkg.main,
format: "cjs"
},
{
file: pkg.module,
format: "esm"
}
];
export default output_data.map(({ file, format }) => ({
input: "src/index.js",
output: {
file,
format,
globals
},
plugins,
external
}));
Anyone have any idea why the ESM version of this lib either wouldn't be published or installed?
Late reply but I ran into something very similar today. Not using rollup but rather tsc directly to output dist/cjs/* and dist/esm/*.
I found that my build process locally produced both outputs but the tarball produced by yarn publish only contained dist/cjs/*. TBH I'm not sure why; my current theory is that yarn is somehow using the "main": "dist/cjs/index.js" and inferring some defaults for package inclusion from that.
What I can tell you is that by adding "files": "dist" to my package.json I got yarn to behave itself and add both dist/cjs/* and dist/esm/* to the package tarball as I initially expected.
https://docs.npmjs.com/cli/v7/configuring-npm/package-json#files

Set up Webpack and Babel to transpile / polyfill older code

I have an entire legacy AngularJS 1.x application that used to run through gulp and babel. We are transitioning to the newer Angular 2+ but I'm running into an issue trying to get Webpack to actually find and compile the legacy files. I've tried following instructions which are all almost identical like this video:
https://www.youtube.com/watch?v=H_QACBSqRBE
But the webpack config simply doesn't do anything to the existing files. Is there a way to grab a WHOLE FOLDER of older components, that DO NOT have any imports or exports? I feel like entry is supposed to follow the import dependency path but that just doesn't exist for older AngularJS 1.x projects.
Errors are NOT being thrown during the build it just...doesn't transpile or polyfill.
example of what that section of the config looks like:
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
We did this recently. We created "dummy" entry point files to avoid having to change all of our AngularJS files to have require/import statements.
./entry-points/feature1.ts
export const importAll = (r: any): void => {
r.keys().forEach(r);
};
importAll(require.context('./app/feature1', true, /module\.js$/));
importAll(require.context('./app/feature1', true, /(^(?!.*(spec|module)\.js).*\.js)$/));
webpack.config.js
entry: {
'feature1': './entry-points/feature1.ts'
}
More detail here

Babel not compiling ES6 to ES5 Javascript [duplicate]

I have this code:
"use strict";
import browserSync from "browser-sync";
import httpProxy from "http-proxy";
let proxy = httpProxy.createProxyServer({});
and I have installed babel-core and babel-cli globally via npm. The point is when I try to compile with this on my terminal:
babel proxy.js --out-file proxified.js
The output file gets copied instead of compiled (I mean, it's the same as the source file).
What am I missing here?
Babel is a transformation framework. Pre-6.x, it enabled certain transformations by default, but with the increased usage of Node versions which natively support many ES6 features, it has become much more important that things be configurable. By default, Babel 6.x does not perform any transformations. You need to tell it what transformations to run:
npm install babel-preset-env
and run
babel --presets env proxy.js --out-file proxified.js
or create a .babelrc file containing
{
"presets": [
"env"
]
}
and run it just like you were before.
env in this case is a preset which basically says to compile all standard ES* behavior to ES5. If you are using Node versions that support some ES6, you may want to consider doing
{
"presets": [
["env", { "targets": { "node": "true" } }],
]
}
to tell the preset to only process things that are not supported by your Node version. You can also include browser versions in your targets if you need browser support.
Most of these answers are obsolete. #babel/preset-env and "#babel/preset-react are what you need (as of July 2019).
I had the same problem with a different cause:
The code I was trying to load was not under the package directory, and Babel does not default to transpiling outside the package directory.
I solved it by moving the imported code, but perhaps I could have also used some inclusion statement in the Babel configuration.
First ensure you have the following node modules:
npm i -D webpack babel-core babel-preset-es2015 babel-preset-stage-2 babel-loader
Next, add this to your Webpack config file (webpack.config.js) :
// webpack.config.js
...
module : {
loaders : [
{
test : /\.js$/,
loader : 'babel',
exclude : /node_modules/,
options : {
presets : [ 'es2015', 'stage-2' ] // stage-2 if required
}
}
]
}
...
References:
https://gist.github.com/Couto/6c6164c24ae031bff935
https://github.com/babel/babel-loader/issues/214
Good Luck!
As of 2020, Jan:
STEP 1: Install the Babel presets:
yarn add -D #babel/preset-env #babel/preset-react
STEP 2: Create a file: babelrc.js and add the presets:
module.exports = {
// ...
presets: ["#babel/preset-env", "#babel/preset-react"],
// ...
}
STEP 3:- Install the babel-loader:
yarn add -D babel-loader
STEP 4:- Add the loader config in your webpack.config.js:
{
//...
module: [
rules: [
test: /\.(js|mjs|jsx|ts|tsx)$/,
loader: require.resolve('babel-loader')
]
]
//...
}
Good Luck...
npm install --save-dev babel-preset-node5
npm install --save-dev babel-preset-react
...and then creating a .babelrc with the presets:
{
"presets": [
"node5",
"react"
]
}
...resolved a very similar issue for me, with babel 3.8.6, and node v5.10.1
https://www.npmjs.com/package/babel-preset-node5
https://www.npmjs.com/package/babel-preset-react
Same error, different cause:
Transpiling had worked before and then suddenly stopped working, with files simply being copied as is.
Turns out I opened the .babelrc at some point and Windows decided to append .txt to the filename. Now that .babelrc.txt wasn't recognized by babel. Removing the .txt suffix fixed that.
fix your .babelrc
{
"presets": [
"react",
"ES2015"
]
}
In year 2018:
Install following packages if you haven't yet:
npm install babel-loader babel-preset-react
webpack.config.js
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015','react'] // <--- !`react` must be part of presets!
}
}
],
}
Ultimate solution
I wasted 3 days on this
import react from 'react' unexpected identifier
I tried modifying webpack.config.js and package.json files, and adding .babelrc, installing & updating packages via npm, I've visited many, many pages but nothing has worked.
What worked? Two words: npm start. That's right.
run the
npm start
command in the terminal to launch a local server
...
(mind that it might not work straight away but perhaps only after you do some work on npm because before trying this out I had deleted all the changes in those files and it worked, so after you're really done, treat it as your last resort)
I found that info on this neat page. It's in Polish but feel free to use Google translate on it.

Categories