I'm using Next.js for Server Side Rendering of React application (with styled-components) and have issue with Babel plugins I'm using to show name of the components I'm using in code.
This is my .babelrc file:
{
"env": {
"development": {
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
},
"production": {
"presets": "next/babel",
"plugins": [
[
"babel-plugin-styled-components",
{
"displayName": false,
"ssr": true
}
]
]
},
"test": {
"presets": [
[
"env",
{
"modules": "commonjs"
}
],
"next/babel"
]
}
}
}
When I'm running cross-env NODE_ENV=development concurrently "tsc --watch" next
I'm getting these lines - meaning .babelrc is used during copilation:
[1] > Using external babel configuration
[1] > Location: "...../.babelrc"
[1] > Using "webpack" config function defined in next.config.js.
But once I go to dev tools and see some styled-component I can see this: class="sc-iyvyFf gGaJAt" but on my code I have this definition:
const Title = styled.div`
font-size: 40px;
line-height: 1.13;
`
As it seems from documentation example - I should get something like ... <button class="Button-asdf123 asdf123" /> instead of just <button class="asdf123" />. But I don't.
After going deeper I found this issue ( https://github.com/styled-components/styled-components/issues/1103#issuecomment-324302997 ) based on errors I get in browser console that said:
It seems that only the server code is being transpiled and not the client code 😉
So Question: How to test if babel works correctly and .babelrc is being used in all places?
P.S. In my case those classes that I've got on client side had this prefix sc- meaning in my head styled-components. So I was not sure if the plugin from .babelrc works at all or it works, but I haven't set any special property in declaration of styled-components thus get this general prefix sc-
UPDATE Here is my custom next.conf.js I'm using
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const { ANALYZE } = process.env
const path = require('path')
module.exports = {
exportPathMap: function() {
return {
'/': { page: '/' }
}
},
webpack: function(config) {
if (ANALYZE) {
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerPort: 8888,
openAnalyzer: true
})
)
}
config.resolve.alias = {
'styled-components': path.resolve('./node_modules/styled-components/')
}
return config
}
}
Looks like no one has unfortunately answered this before;
What you're seeing probably comes down to this little piece of code you posted: tsc --watch
If you execute TypeScript transpilation before Babel and leave it up to TypeScript to transpile to ES5, it'll transpile all tagged template literals, not giving our plugin anything to hook onto.
Since you're already using next.js you won't need to set up your Babel pipeline from scratch. Rather you only need to disable this type of transpilation in TypeScript.
I'd suggest you to set target inside your tsconfig.json to ESNext so that it leaves everything up to Babel.
https://www.typescriptlang.org/docs/handbook/compiler-options.html (See "--target")
Related
Have got a successful jest/esm setup, however occasionally a module is released that specifies both a main key (for commonjs) and a module key (for ESM) in its package.json. This leads to jest errors, for example with the uuid module:
/repo/path/node_modules/uuid/dist/esm-browser/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';
^^^^^^
SyntaxError: Unexpected token 'export'
I can see that dist/esm-browser/index.js is the file specified by the module key in package.json.
How can Jest w/ESM be configured to handle these cases, where stuff in node_modules is ESM?
Jest config:
{
"resetMocks": true,
"testEnvironment": "jsdom",
"testMatch": [
"**/src/**/*.(spec|test).[tj]s?(x)"
],
"preset": "ts-jest/presets/default-esm",
"extensionsToTreatAsEsm": [
".ts",
".tsx"
],
"globals": {
"ts-jest": {
"useESM": true
}
},
"globalSetup": "<rootDir>/jest/setup.cjs",
"globalTeardown": "<rootDir>/jest/teardown.cjs",
"watchPathIgnorePatterns": [
"<rootDir>/.tmp"
],
"moduleNameMapper": {
"^~/(.*)$": "<rootDir>/src/$1",
"^~components/(.*)$": "<rootDir>/src/components/$1",
"^~util/(.*)$": "<rootDir>/src/util/$1",
"^~types/(.*)$": "<rootDir>/src/types/$1"
}
}
If transformIgnorePatterns doesn't work for some reason, you can solve it with moduleNameMapper.
moduleNameMapper: {
// '^uuid$': '<rootDir>/node_modules/uuid/dist/index.js',
'^uuid$': require.resolve('uuid'),
}
I've had the same problem and it was fixed the same way as mentioned in this comment: https://github.com/nrwl/nx/issues/812#issuecomment-429420861 in my jest.config.js:
// list to add ESM to ignore
const esModules = ['uuid'].join('|');
// ...
module.exports = {
//...
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
// ...
};
I am encountering very weird behavior of babel path transpilation. in my project some modules are called as following
import module from '~modulename'
where ~ means import given 'modulename' from root of project directory. now how this works fine for dev (babel-node for running project). but when i run babel src -d lib on my project for transpiling es6 js everything is converted (trans piled) but this path doesn't so in build i am always left with require('~modulename') instead require('../../...modulename').
Solutions i have tried
aliasing ~ to ./ in babel.config.js through module-resolver-plugin
Babel.config.js
module.exports = __babel => {
// Use cache.
__babel.cache(true)
// Return configuration.
return {
'presets': [
[
'#babel/preset-env',
{
'modules': false
}
]
],
'plugins': [
'#babel/plugin-proposal-throw-expressions',
'#babel/plugin-proposal-export-default-from',
'dynamic-import-node',
'babel-plugin-root-import',
['babel-plugin-module-resolver', { 'alias': { '~': './' } }]
['module-resolver', { 'root': ['./', 'packages/*'] }],
['#babel/plugin-transform-modules-commonjs', { 'allowTopLevelThis': true }],
['#babel/plugin-transform-runtime', { 'regenerator': true }]
],
'env': {
'production': {
'presets': ['minify'],
'plugins': [
'transform-remove-console',
'minify-dead-code-elimination'
]
}
}
}
}
While I am aware that Babel is capable of transpiling TypeScript itself, I've had enough weird issues I'd like to first transpile TypeScript->JS and then run Babel on that.
I've got my tsconfig.json files working as expected. When I compile my TypeScript (from ./src folder relative to babel.config.json's path), it outputs to a ./build folder. I have Babel set to take what's in the ./build folder and output to the ./dist folder.
The output of TSC shows import {bar} from 'foo' and import {thing} from 'foo/util', as expected. But Babel's output looks like ../../../libfoo/libfoo.js when it should be ../../libfoo/libfoo.js
No matter what I try with root/cwd, I can't seem to get that extra ../ to disappear. I've managed to make it go away a couple times, but then I rebuild without changing the babel config, and it comes back.
My babel.config.json currently looks like this:
{
"presets": [
["#babel/preset-env", {"targets": {
"node": true,
"electron": "80"
}}],
["#babel/preset-typescript", { "onlyRemoveTypeImports": true }]
],
"plugins": [
["babel-plugin-module-resolver", {
"alias": {
"^foo/(.+)": "./libfoo/\\1.js",
"^foo$": "./libfoo/libfoo.js"
}
}],
["#babel/plugin-transform-modules-umd"],
["#babel/plugin-transform-typescript", {
"allowNamespaces": true,
"allowDeclareFields": true,
"onlyRemoveTypeImports": true
}],
["#babel/plugin-proposal-pipeline-operator", { "proposal": "fsharp" }],
"#babel/plugin-proposal-nullish-coalescing-operator",
"#babel/plugin-proposal-optional-chaining",
"#babel/plugin-proposal-do-expressions",
"#babel/plugin-proposal-logical-assignment-operators",
"#babel/plugin-proposal-partial-application",
["#babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-throw-expressions",
"#babel/plugin-proposal-export-default-from",
"#babel/plugin-proposal-export-namespace-from",
"#babel/plugin-proposal-function-bind"
],
"sourceMaps": true
}
Well, I found a solution that doesn't really fix the problem but makes it works.
My files structure is something like this:
|-dist
|-src
|-db
|-connect
|-index.ts
|-index.ts
|-.babelrc
When babel compiles the code, the import of db/connect in src/index.ts, go from this:
import ... from "db/connect"
to this:
var _connect = require("../db/connect");
To resolve this, I simply add /dist to the paths in .babelrc
before:
[
"module-resolver",
{
"root": ["./"], # or ["src"] or "src" or ["./src"] or "./src" or any way you can imagine
"alias": {
"db": "./db",
}
}
}
]
after:
[
"module-resolver",
{
"alias": {
"db": "./dist/db",
}
}
}
]
And the import is now:
var _connect = require("../dist/db/connect");
As you said, the root doesn't affect the require path, so I just removed it.
This doesn't fix the problem, but makes it work.
Hope it helps, good luck! :)
In an Express.js app, I'm using Babel to precompile to commonjs before starting it. The compilation step looks like this:
babel ./src --out-dir dist
node ./dist/bin
As part of the project I have a file called my-worker.js where I use import syntax:
# my-worker.js
import { parentPort, workerData } from 'worker_threads'
import axios from 'axios'
...
And that is used by other-file.js:
#other-file.js
...
const worker = new Worker(__dirname + '/my-worker.js', { workerData: ... })
...
This works fine. Babel converts all the files to commonjs, and loading the worker script works.
BUT
When I use #babel/node, this doesn't work:
babel-node ./src/bin
I get the warning:
(node:4865) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
Along with the error:
Cannot use import statement outside a module
I don't want to use "type": "module", since then I have to explicitly name file extensions, and also I'm not sure that import X, { y } from ... syntax is supported (which I like).
If I change my worker file to be my-worker.mjs, and change the new Worker statement accordingly, then that works with #babel/node, but not with my production build since filenames are changed back to .js.
How can I get #babel/node to load and cache (I guess this is what it needs to do?) files loaded by a Worker? Why does this work with #babel and not with #babel/node?
My .babelrc file looks like this:
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3,
"targets": {
"node": "13"
},
"modules": "commonjs"
}
]
]
}
The #babel/register API can help dynamically transpile a script source, as pointed out in https://github.com/babel/babel/issues/10972#issuecomment-572608142
You can use this approach with eval mode to make a single-file script. This might be useful if you use babel-node to run a command-line utility script.
import { isMainThread, Worker, workerData } from "worker_threads";
function createTranspiledWorker(filename, options) {
const transpile = `
require('#babel/register');
require(${JSON.stringify(filename)});
`;
return new Worker(transpile, { ...options, eval: true });
}
async function main() {
const w = createTranspiledWorker(__filename, { workerData: { hello: "world" } });
const exit = new Promise(resolve => w.on("exit", resolve));
await exit;
}
function worker() {
console.log("worker", workerData);
}
if (isMainThread) {
main();
} else {
worker();
}
I'm desperately trying to make my NuxtJS app work with IE11. I implemented babel config in many ways to build a compatible version but I still have spread operators in built pages files, as if Babel didn't transform Nuxt code.
Here is my config:
nuxt.config.js
const pkg = require('./package')
const path = require('path');
module.exports = {
mode: 'universal',
// ...
build: {
babel: {
babelrc: true
},
extend(config, ctx) {
config.resolve.modules.push(path.resolve(__dirname, 'assets'));
const svgRule = config.module.rules.find(rule => rule.test.test('.svg'));
svgRule.test = /\.(png|jpe?g|gif|webp)$/;
config.module.rules.push({
test: /\.svg$/,
loader: 'vue-svg-loader',
}, {
test: /\.js$/,
loader: 'babel-loader'
})
}
}
}
.babelrc
{
"presets": [["#babel/preset-env", { "modules": false }]],
"plugins": [
"#babel/transform-runtime",
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-transform-spread",
"#babel/plugin-proposal-object-rest-spread"
],
"env": {
"test": {
"presets": [["#babel/preset-env", { "targets": { "node": "current" } }]]
}
}
}
.browserslistrc
# Browsers that we support
>0.2%
not dead
not ie < 11
not op_mini all
Despite that config, I still see some spread operators used in Nuxt built pages, like the following generated by nuxt:
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["pages/events/_slug.pages/index"],{
/***/ "./assets/svg/events/market.svg":
/*!**************************************!*\
!*** ./assets/svg/events/market.svg ***!
\**************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = ({
functional: true,
render(_h, _vm) {
const { _c, _v, data, children = [] } = _vm;
const {
class: classNames,
staticClass,
style,
staticStyle,
attrs = {},
...rest
} = data;
I searched from some time across different issues about NuxtJS and Babel, but Nuxt claims that it works with IE9 without extra Babel configuration, which is not the case here. I'd like to understand why the code is not transpiled the right way.
I ran into a similar issue: A Nuxt app wouldn't work in the Edge browser because of spread operators in #nuxtjs/axios and bootstrap-vue. I did find a solution.
The build property in nuxt.config.js should be defined as follows:
build: {
babel: {
babelrc: true,
configFile: './babel.config.js'
},
transpile: [ '#nuxtjs/axios', 'bootstrap-vue' ],
// Other config
}
The transpile property is key here. Internally, Nuxt defines an exclude for babel-loader that ignores everything in node_modules, unless it's in transpile.
Using babel.config.js also appears to matter, and the official Babel documentation says you should use it if you want to process node_modules.
babel.config.js:
module.exports = function (api) {
api.cache(true);
return {
sourceType: 'unambiguous',
presets: ['#nuxt/babel-preset-app'],
plugins: ['#babel/plugin-proposal-object-rest-spread']
};
}
You don't need include or exclude here, as it's taken care of by Nuxt, as noted.