NuxtJS with Babel 7: still have spread operator in built files - javascript

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.

Related

Webpack erroring on mini-css-extract-plugin loader

When I try to use the loader for mini-css-extract-plugin webpack returns the following error:
/node_modules/mini-css-extract-plugin/dist/loader.js:122
for (const asset of compilation.getAssets()) {
^
TypeError: compilation.getAssets(...) is not a function or its return value is not iterable
I am requiring the plugin and invoking the loader in my prod config file:
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const path = require("path");
const common = require("./webpack.common");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = merge(common, {
mode: "production",
output: {
filename: "[name].[contentHash].bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new MiniCssExtractPlugin({filename: "[name].[contentHash].css"}),
new CleanWebpackPlugin()
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader, //3. Extract css into files
"css-loader", //2. Turns css into commonjs
"sass-loader" //1. Turns sass into css
],
},
],
},
});
I have it included in my devDependencies:
"mini-css-extract-plugin": "^1.3.6",
But still I receive the error. I haven't found anything in the [documentation][1] to indicate what could be happening. Is there something I'm overlooking with this code?
Why would methods from loader.js be getting flagged as 'not a function?'
[1]: https://www.npmjs.com/package/mini-css-extract-plugin
I understand getAssets is only available since webpack 4.40.0 https://webpack.js.org/api/compilation-object/#getassets
You could try:
Update webpack version to at least 4.40.0
Downgrade min-css-extract-plugin to 1.3.0
I tried the second one, and worked for me, but upgrading webpack should work too.

Transpiling to ES5 using webpack 4 and Babel

I'm still using webpack 4.28.4 for organizational reasons. We are trying to transpile some of our code to support ES5 using Babel 7, but our resulting bundle is throwing console errors when loaded in a browser (Chromium v44). We have seen some of the newer options available in webpack 5, which some of my colleagues have been able to use to resolve similar failures:
output.environment.arrowFunction = false
target = 'es5'
Is there some sort of equivalent approach for webpack 4? Do we just need to find the right combination of Babel plugins to fully convert to ES5?
The console error we get in Chromium 44 is always an "Uncaught SyntaxError: Unexpected token )" in some low level Dojo JavaScript file which we know is unchanged and should be a valid function.
Here's a cleaned up version of our webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const BabelLoaderPlugin = require('babel-loader');
const BabelPreset = require('#babel/preset-env');
const makeConfig = ({
component_path,
js_module,
entryPoints = {"index": js_module + "/entryPoint",
"index-css": js_module + "/css/main"},
outputPublicPath = 'release/',
outputPath = path.resolve(component_path, 'release'),
dev_mode = 'production',
babel_chrome_level = "44",
} = {}) => {
return {
entry: entryPoints,
output: {
path: outputPath,
publicPath: outputPublicPath,
pathinfo: true,
filename: "bundle.[name].js"
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components|dojo)/,
use: {
loader: 'babel-loader',
query: {
babelrc: false,
presets: [
[BabelPreset,
{
"exclude": ["transform-regenerator"],
"targets": {
"chrome": babel_chrome_level
}
}]
],
plugins: [
require("#babel/plugin-transform-async-to-generator"),
require("#babel/plugin-transform-arrow-functions"),
require("#babel/plugin-transform-modules-commonjs")
]
}
}
},
]
},
plugins: [
...
],
};
}
module.exports = { makeConfig };
Did you try to hardcoded it to 44 instead of using babel_chrome_level?
In Chrome devtools, you might be able to get it to pretty-print the minified Dojo sources to better identify exactly which feature it's tripping over
The better fix for this is to find whatever numbskull in your organization has you stuck on a FIVE YEAR OLD version of a browser and smack them until they stop
Also it looks like you're explicitly excluding dojo from your Babel transform
I don't know much about Dojo -- I guess they made a totally new "modern" version at some point? -- but maybe you can pin to an older version of it that officially supports your version of Chrome?

How to exclude core-js using useBuiltIns: "usage"

Using babel 7.5.5, core-js 3.1.4 and webpack 4.38.0, how can I exclude core-js from transpiling?
I do not want to exclude node_modules altogether since I have libs that need transpiling
If I use exclude: /node_modules\/(core-js)/, a core-js module throws
TypeError: $ is not a function
This leaves me with two other options.
Use includes instead, include my src directory and every dependency that needs transpiling one by one
Use useBuiltIns: entry instead of usage, since in this case exclude: /node_modules/\(core-js)/ works, and import core.js at the top of main.js
Both of these options don't really seem like good solutions to me since usage is "no longer experimental" since 7.4.
Is there any way to make it work using usage? Is it a bug in either babel-loader or babel? Or is my configuration at fault?
This is my Webpack config:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
main: ['./src/main'],
},
output: {
path: path.resolve(__dirname, './build/'),
publicPath: '/build/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(core-js)/,
use: {
loader: 'babel-loader'
},
},
{
test: require.resolve('jquery'),
use: [
{
loader: 'expose-loader',
options: 'jQuery'
},
{
loader: 'expose-loader',
options: '$'
}
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
};
This is my babel config:
module.exports = function (api) {
api.cache(true);
return {
presets: [
[
'#babel/preset-env',
{
corejs: {
version: 3,
},
useBuiltIns: 'usage',
}
]
],
};
};
You can reproduce the error with the following repository: https://github.com/tomm1996/usebuiltins-exclude-test
You need to exclude both core-js and webpack/buildin from the Babel transpilation.
You can use the folling exclude Regexes:
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/
]
Here is also a complete babel-loader configuration with some useful comments:
{
module : {
rules : [{
test : /\.js$/,
// Some module should not be transpiled by Babel
// See https://github.com/zloirock/core-js/issues/743#issuecomment-572074215
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/
],
loader : "babel-loader",
options : {
babelrc : false,
// Fixes "TypeError: __webpack_require__(...) is not a function"
// https://github.com/webpack/webpack/issues/9379#issuecomment-509628205
// https://babeljs.io/docs/en/options#sourcetype
sourceType : "unambiguous",
presets : [
["#babel/preset-env", {
// Webpack supports ES Modules out of the box and therefore doesn’t require
// import/export to be transpiled resulting in smaller builds, and better tree
// shaking. See https://webpack.js.org/guides/tree-shaking/#conclusion
modules : false,
// Adds specific imports for polyfills when they are used in each file.
// Take advantage of the fact that a bundler will load the polyfill only once.
useBuiltIns : "usage",
corejs : {
version : "3",
proposals : true
}
}]
]
}
}
}
}
See https://github.com/zloirock/core-js/issues/743#issuecomment-572074215
Edit: Also if you try to use #babel/plugin-transform-runtime:
plugins : [
// Require the Babel runtime as a separate module to avoid the duplication
// https://webpack.js.org/loaders/babel-loader/#babel-is-injecting-helpers-into-each-file-and-bloating-my-code
["#babel/plugin-transform-runtime", {
// Requires #babel/runtime-corejs3
// https://babeljs.io/blog/2019/03/19/7.4.0#migration-from-core-js-2
corejs : { version: 3, proposals: true }
}],
}
You may run into a similar error:
Uncaught TypeError: _typeof2 is not a function
at _typeof (typeof.js:8)
at eval (sockjs.js:123)
at Object.eval (sockjs.js:131)
at eval (sockjs.js:6565)
at Object../node_modules/sockjs-client/dist/sockjs.js (main.js:13790)
at __webpack_require__ (main.js:70)
at eval (webpack://PUBLIC_ENGINE/(:8000/webpack)-dev-server/client/clients/SockJSClient.js?:110:14)
at Object../node_modules/webpack-dev-server/client/clients/SockJSClient.js (main.js:13874)
at __webpack_require__ (main.js:70)
at eval (webpack://PUBLIC_ENGINE/(:8000/webpack)-dev-server/client/socket.js?:56:41)
This can be solved by excluding #babel/runtime-corejs3 from the transpilation:
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/,
/#babel\/runtime-corejs3/
]

webpack can convert js to es6?

I using webpack to bundle my node application.
I see the result in the bundle that webpack convert from const to var. This is mean that webpack convert my files to es5.
How can I tell webpack to convert to es6? (leave the const as it is and/or use import keyword for example)
app.js
import {test} from './some';
const x = 1;
console.log('test', test);
console.log('this should be const in the bundle, not var. ', x);
And the bundle is:
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _some__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./some */ "./some.js");
var x = 1;
console.log('test', _some__WEBPACK_IMPORTED_MODULE_0__["test"]);
console.log('this should be const in the bundle, not var. ', x);
/***/ }),
my webpack config:
const path = require('path');
module.exports = () => [
{
mode: 'development',
entry: path.resolve(__dirname, './app.js'),
output: {
path: path.resolve(__dirname, './dist')
},
devtool: 'source-map',
target: 'node',
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
}
}
];
You are using the #babel/preset-env without any options. That will transform the code to ES5 and the documentation says it's not really recommended to use it this way. The whole point of the "env" preset is that you give a target platform and it will automatically apply the transformations, which are needed for that platform. Passing "targets.node"-option value true or "current" will transform the code for the currently used node-version. Using the preset with this option has the additional advantage, that upgrading node.js will not require any changes in Babel configuration and less code will be transformed, if the new node.js supports more of the ES features used.
Support for ECMAScript modules in node.js is still experimental, but you can disable module transformation by passing false to "modules"-option.
options: {
presets: [[
'#babel/preset-env',
{
targets: {
node: "current"
},
modules: false
}
]]
}

Vue Cli 3 is not allowing me to process SVG's in Webpack

Vue Cli defaults to file-loader for SVG assets, but I want to use svg-sprite-loader (as well as a few others) instead.
I updated the vue.config.js file to do this and it still seems to use file-loader. Almost as though it's not picking up my config at all.
vue.config.js
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.(svg)(\?.*)?$/,
use: [
{
loader: 'svg-sprite-loader',
options: {
name: '[name]-[hash:7]',
prefixize: true
}
},
'svg-fill-loader',
'svgo-loader'
]
}
]
}
}
}
Is there anything wrong with my setup?
I'm still getting SVG files imported into my component as a URL string / path when it should be an object with properties.
Many thanks.
This took me a while to find a work around. Basically you need to stop file-loader matching on .svg. The best way I have found to do this is using chainWebpack and returning false from the test method on file-loader. I have included my working config.
module.exports = {
lintOnSave: false,
configureWebpack: {
module: {
rules: [
{
test: /\.(svg)(\?.*)?$/,
use: [
{
loader: 'svg-inline-loader',
options: {
limit: 10000,
name: 'assets/img/[name].[hash:7].[ext]'
}
}
]
}
]
}
},
chainWebpack: config => {
config.module
.rule('svg')
.test(() => false)
.use('file-loader')
}
}
The Webpack docs for Vue CLI 3.0 beta got updated with an example on how to replace an existing Base Loader. For svg-sprite-loader this means that you'll have to add the following configuration to your vue.config.js:
chainWebpack: config => {
config.module
.rule('svg')
.use('file-loader')
.loader('svg-sprite-loader')
}
I'm using Vue CLI 3.0.3 and this config works for me 😉
const path = require('path');
const glob = require('glob');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
module.exports = {
lintOnSave: false,
configureWebpack: {
plugins: [
new SpriteLoaderPlugin()
]
},
chainWebpack: config => {
config.module.rules.delete('svg');
config
.entry('app')
.clear()
.add(path.resolve(__dirname, './src/main.ts'))
config
.entry('sprite')
.add(...glob.sync(path.resolve(__dirname, `./src/assets/icons/*.svg`)));
config.module.rule('svg')
.test(/\.(svg)(\?.*)?$/)
.use('file-loader')
.loader('svg-sprite-loader')
.options({
extract: true,
spriteFilename: 'icons.svg'
})
}
};
Vue CLI docs for version 3.x in webpack section suggests to use something like this:
// vue.config.js
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// clear all existing loaders.
// if you don't do this, the loader below will be appended to
// existing loaders of the rule.
svgRule.uses.clear()
// add replacement loader(s)
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
}
Even vue-svg-loader configuration guide suggests same approach.
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
svgRule.clear()
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
}

Categories

Resources