webpack: Babel 7 not being executed on webpack.config.babel.js

What is the current behavior?

Executing webpack with a ES6+ config file (webpack.config.babel.js) whilst using Babel 7 leads to a SyntaxError being reported e.g.

$ webpack --env.production
<OMITTED>/webpack.config.babel.js:1
(function (exports, require, module, __filename, __dirname) { import path from 'path'
                                                              ^^^^^^

SyntaxError: Unexpected token import

If the current behavior is a bug, please provide the steps to reproduce.

  1. Install the latest webpack and the latest @babel/core & @babel/preset-env (e.g 7.0.0-beta.32)

  2. Create a webpack.config.babel.js with ES6+ syntax e.g.

    echo "import path from 'path'" > webpack.config.babel.js
    

    Note: For illustrative purposes only, this obviously doesn’t produce a valid webpack config, but it’s sufficient to recreate the issue.

  3. Create a .babelrc with the env preset:

    echo "{\"presets\":[\"@babel/env\"]}" > ./.babelrc
    
  4. Run webpack e.g.

    webpack
    

What is the expected behavior?

Babel to to be executed on webpack.config.babel.js before Node executes the file.

Following the steps above you’re expecting a webpack specific error regarding an invalid configuration:

<OMITTED>/node_modules/webpack/bin/convert-argv.js:507
				throw new Error("'output.filename' is required, either in config file or as --output-filename");

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

webpack: 3.8.1 @babel/core: 7.0.0-beta.32 @babel/preset-env: 7.0.0-beta.32

What I’m assuming is happening is that Webpack is looking for the presence of a babel-core package, can’t find it, so proceeds without using babel. Babel 7 has scoped packages, the new package is @babel/core.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 24
  • Comments: 28 (3 by maintainers)

Most upvoted comments

This exact issue is happening to me on Webpack 4.20.2 still.

For anybody still wondering in this thread or people who got here from google like me. This is caused by a bug in webpack-cli and will be fixed after this merging this PR https://github.com/webpack/webpack-cli/pull/728

Another workaround when using the CLI.

Create a webpack.config.js file which calls babel register and your webpack.config.babel.js

I have also gotten this problem. In my occasion, adding @babel/register works for me.

yup!

I just now managed to get it working though, with an extra install of @babel/register. So this is my setup now:

package.json

"dependencies": {
  "@babel/core": "^7.1.2",
  "@babel/preset-env": "^7.1.0",
  "@babel/register": "^7.0.0",
  ...
  "webpack": "^4.20.2",
},

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "targets": {
          "node": "current"
        }
      }
    ]
  ]
}

webpack.config.babel.js

import { xyz } from 'xyz';
...

@kud the register is for making Babel do the transpiling at runtime, it’s what interpret uses

@kud try installing @babel/register as I’ve suggested in the comment right above yours 😉

interpret was updated

@laozhu We’re waiting on the following procedure:

  • interpret PR I mentioned above to be modified/accepted and merged.
  • A new interpret release to be published.
  • webpack to bump its dependency on interpret.
  • A new webpack release.

So this issue is effectively blocked by interpret for now.

However, there are several work-arounds that may be appropriate for various use-case:

  1. Manually run babel on your config before running webpack (cli):

package.json

{
  ...
  "scripts": {
    ...
    "build": "babel webpack.config.babel.js > webpack.config.js; webpack --env.production",
    ...
  },
...

This is fine for packaging up for production, but may not be ideal during development.

  1. Call webpack’s compiler from a JS entry-point, here’s an example that does just that and also supports server-side hot-reloading:

<project_root>/start-hot.js

require('@babel/register')

const webpack = require('webpack')

const serverConfig = require('./webpack.config.babel').serverConfig

const environment = process.env.NODE_ENV === 'development' ? {development: true} : {production: true}
const config = serverConfig({...environment})
const bundlePath = `${config.output.path}/${config.output.filename}`;

const compiler = webpack(config)
const compilerOptions = {
    aggregateTimeout: 300,
    poll: true,
}

let server = null

const openSockets = new Map()
let nextSocketId = 0

function loadServer() {
    delete require.cache[require.resolve(bundlePath)]
    server = require(bundlePath).default

    server.on('connection', (socket) => {
        const socketId = nextSocketId++
        openSockets.set(socketId, socket)

        socket.on('close', () => {
            openSockets.delete(socketId)
        })
    })

}

compiler.watch(compilerOptions, err => {
    if (err) {
        console.log(`Server bundling error: ${JSON.stringify(err)}`)
        return
    }

    if (server) {
        for (const socket of openSockets.values()) {
            socket.destroy()
        }

        server.close(() => {
            loadServer()
            console.log('Server restarted')
        })
    } else {
        loadServer()
        console.log("Server started.")
    }
})

package.json

{
  ...
  "scripts": {
    ...
    "debug-hot": "NODE_ENV=development node ./start-hot.js",
    ...
  },
...

I’m using @babel/register here, so you’ll need to add it as a dev dependency if you haven’t already.

For anyone curious, @babel/register modifies require so Babel transpilation will be run on the fly on required files (namely webpack.config.babel.js).

Note that I’m only compiling the server configuration, which in my case is exported as a function, you may need to adjust accordingly. I’m only compiling the server because I’m running Webpack’s HMR for the client bundle, as part of my server. If you’re not, you can modify the code above to load the client config and instantiate a second compiler.

There are packages out there that do something very similar to the provided start-hot.js, but they’re opinionated (as is my solution) - however, you can customise as you see fit.