为啥我必须将 babel-presets 放在 .babelrc 和 webpack.config.js 中?

Posted

技术标签:

【中文标题】为啥我必须将 babel-presets 放在 .babelrc 和 webpack.config.js 中?【英文标题】:why do I have to put babel-presets inside .babelrc and webpack.config.js?为什么我必须将 babel-presets 放在 .babelrc 和 webpack.config.js 中? 【发布时间】:2017-08-29 14:02:04 【问题描述】:

好的。我正在引导一个简单的应用程序。我正在使用 flow.js。我使用的预设是 babel-preset-2015、babel-preset-react 和 babel-preset-stage-0。我必须在我的 .babelrc 和我的 webpack.config 中放置相同的预设,这样它才能正常工作。例如,如果我从 webpack.config 中删除它们,我会收到错误“未定义 React”。如果我删除 .babelrc 和 babel-register ,我会收到一个错误,因为我使用了 import 和 Flow.js 注释。为什么会这样?如果我将预设放在 webpack.config 中,我应该能够删除 .babelrc ,反之亦然。这就是我的代码在一切正常时现在的样子(减去一些对问题不重要的文件)。

start-dev.js

require('babel-register')
require('./src/server/index.js')

index.js

/* @flow */

import Express from 'express'
import path from 'path'
import conf from '../conf/'

const APP_PORT: number = conf.APP_PORT
const PORT = process.env.PORT || APP_PORT

const app: Express = new Express()

// Middleware
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.use(Express.static(path.join(__dirname, '../', 'client', 'dist')))

// Routes
app.get('*', function (req: Object, res: Object) 
  res.render('index')
)

app.listen(PORT, function () 
  console.log(`Express server is up on port $PORT`)
)

app.js

import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <h1>First</h1>,
  document.getElementById('app')
)

package.json


  "scripts": 
    "start-dev": "set \"NODE_ENV=development\" && babel-node ./start-dev.js",
    "start": "set \"NODE_ENV=development\" && node ./start-dev.js",
    "flow": "./node_modules/.bin/flow check",
    "standard": "node_modules/.bin/standard --verbose | node_modules/.bin/snazzy"
  ,
  "dependencies": 
    "ejs": "^2.5.6",
    "express": "^4.15.2",
    "react": "^15.4.2",
    "react-dom": "^15.4.2"
  ,
  "devDependencies": 
    "babel-cli": "^6.24.0",
    "babel-core": "^6.24.0",
    "babel-eslint": "^7.2.1",
    "babel-loader": "^6.4.1",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "babel-preset-stage-0": "^6.22.0",
    "babel-register": "^6.24.0",
    "eslint": "^3.18.0",
    "eslint-config-standard": "^7.1.0",
    "eslint-plugin-flowtype": "^2.30.4",
    "eslint-plugin-react": "^6.10.3",
    "flow-bin": "^0.42.0",
    "snazzy": "^6.0.0",
    "standard": "^9.0.2",
    "webpack": "^2.3.2"
  

.babelrc


  "passPerPreset": true,
  "presets": [
    "es2015",
    "react",
    "stage-0"
  ]

webpack.config.babel.js

'use strict'

import path from 'path'
const publicPath = path.resolve(__dirname, './src/client')

module.exports = 
  devtool: '#source-maps',
  performance: 
    hints: false
  ,
  context: publicPath,
  entry: 
    bundle: './app.js'
  ,
  output: 
    path: path.join(publicPath, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/'
  ,
  resolve: 
    extensions: ['.js', '.jsx']
  ,
  module: 
    rules: [
      
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: 
          presets: [
            'react',
            'es2015',
            'stage-0'
          ]
        
      
    ]
  

【问题讨论】:

babeljs.io/docs/en/config-files >>> babeljs.io/docs/en/next/configuration >>>sebastiandedeyne.com/whats-in-our-babelrc 【参考方案1】:

尝试修改您的加载器,例如

module: 
    rules: [
      
        test: /\.jsx?$/,
        exclude: [/node_modules/],
        use: [
          loader: 'babel-loader',
          options:  presets: ['react','es2015', 'stage-0'] 
        ],
      
    ]
  

【讨论】:

这在 webpack 2 中不再需要了。 resolve.extensions 这个选项不再需要传递一个空字符串。此行为已移至 resolve.enforceExtension。请参阅解决以了解更多用法。 谢谢,但运气不好。如果我这样说并删除 .babelrc 我会收到错误的意外令牌导入【参考方案2】:

如果我将预设放在 webpack.config 中,我应该能够删除 .babelrc,反之亦然。

不,事实并非如此。在 webpack 配置中指定预设只会影响 webpack,其他所有使用 babel(例如babel-nodebabel-register 等)的东西都不会关心您的 webpack 配置,因此不会看到它们。

反之亦然。因此,如果您有 .babelrc,则可以删除 webpack 预设选项,因为 babel-loader 在后台使用 babel,这显然尊重 .babelrc

例如,如果我从 webpack.config 中删除它们,我会收到错误 React is not defined

问题是你的.babelrc 配置与webpack config 中的配置不同。罪魁祸首是"passPerPreset": true。使用此选项,每个预设都将单独应用,而不考虑其他预设。为此,顺序很重要。来自babel docs - Plugin/Preset Ordering:

预设顺序颠倒(从后到前)。

这意味着它们将按以下顺序应用:stage-0reactes2015。由于它们是单独应用的,react 会将 JSX 转换为 React.createElement,因为 React 在范围内,es2015 将仅将导入转换为 _react2.default,因此不再定义 React。两个捆绑包之间的整个差异是这样的:

@@ -9470,7 +9470,7 @@ function _interopRequireDefault(obj)  return obj && obj.__esModule ? obj :  de
// var React = require('react')
// var ReactDOM = require('react-dom')

-_reactDom2.default.render(React.createElement(
+_reactDom2.default.render(_react2.default.createElement(
  'h1',
  null,
  'Juhuuuu'

关于passPerPreset 的信息不多,但它在Release notes 中被标记为实验性的,您应该完全避免使用它。

虽然如果您将 react 预设放在列表的第一位,它会起作用,但我建议您删除 passPerPreset 选项,除非您有非常具体的理由使用它。


  "presets": [
    "es2015",
    "react",
    "stage-0"
  ]

【讨论】:

感谢迈克尔,这很有效。将 react 放在 .babelrc 中,我能够从 config.js 中删除预设,它仍然有效。我还有几个问题可以更好地理解。如果我从我的 start-dev.js 文件的顶部删除 babel-register 它不起作用。 babel-register.babelrc 有什么关系,babel-registerbabel-node 有什么区别乙>?据说使用 babel-registerbabel-node 不利于生产,最好在部署之前提前编译。最好的方法是什么? babel-register 将转换您导入的任何文件,而 babel-node 将仅转换您正在运行的文件,而不是它导入的所有文件。正式属于 babel 的所有内容都将尊重您 .babelrc 中的配置,除非您明确告诉它不要这样做(例如使用 --no-babelrc flag)。要构建生产环境,您可以使用babel-cli,请参阅Compile Directories。 Webpack 也可用于捆绑后端。 好的。我想我明白了。所以在开发中,如果我用 babel-register 或 babel-node 测试它实际上并不重要。在生产中最好只使用 babel。我刚才试过了,我还有最后一个问题。使用 babel-cli 后,我得到了一个 lib 文件夹,其中包含我项目中的所有文件夹,包括新的 bundle.js。我一直在使用 webpack 来制作 bundle.js,然后在 index.html 中我有一个带有 src 的 你不应该转译与 webpack 一起使用的文件,无论是源代码还是包,它们已经是,你所需要的只是包(它是独立的)。 Webpack 将您的应用程序所需的一切都放入包中,以使其在浏览器中运行。您只需要转译服务器文件(显然不包含在 webpack 包中),然后简单地使用它来提供包。虽然 webpack 可以用于后端,但它主要用于创建要在浏览器中运行的包,它允许您使用 npm 模块。 谢谢迈克尔。不幸的是,我仍然不清楚这方面的一些问题,但我将关闭这个问题并打开一个新问题,以便对 webpack、bundle 和生产进行更广泛的讨论。感谢您的帮助。

以上是关于为啥我必须将 babel-presets 放在 .babelrc 和 webpack.config.js 中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要将 e.target.name 放在方括号 [] 中? [复制]

为啥动画没有像预期的那样将盒子放在底部

为啥 `UseAuthentication` 必须放在 `UseRouting` 之后而不是之前?

idea中为啥配置了maven还需要额外的jar包必须放在web-inf的lib中吗

switch结构case语句后的多个语句必须放在花括号中。 这句话对吗?为啥?

为啥 Xcode 将 DerivedData 放在我的项目文件夹中?