Webpack с загрузчиком babel, не выдающим действительный es5

У меня есть конфигурация веб-пакета, основанная на https://github.com/vuejs-templates/webpack-simple/blob/master/template/webpack.config.js Он использует vue-loader и babel-loader. Проблема в том, что я не могу заставить его генерировать код ES5, чтобы он работал с самым широким кругом клиентов.

Если я использую предустановку ES2015, webpack.optimize.UglifyJsPlugin не удастся минимизировать вывод, потому что Uglify может обрабатывать только ES5 (не считая ветви гармонии). Ошибки похожи на: Unexpected token: punc (() и возникают в нескольких файлах.

Я могу обойти это, используя babili-webpack-plugin, который минимизирует код ES6, но работает очень медленно. Однако, когда я развертываю этот код, я вижу, что в ответе об ошибках сообщается Block-scoped declarations (let, const, function, class) not yet supported outside strict mode, поэтому я знаю, что это старые клиенты, которые задыхаются от кода ES6.

Как я могу получить правильный вывод кода ES5 из babel-loader? Я пробовал несколько пресетов, с плагином transform-runtime или без него. Конфигурация ниже:

const webpack = require('webpack');
const globEntries = require('webpack-glob-entries');
const _ = require('lodash');
const path = require('path');
const BabiliPlugin = require("babili-webpack-plugin");

const env = process.env.NODE_ENV;

let entries;
if (env === 'production') {
  entries = globEntries('./src/**/vue/*.js');
} else {
  entries = _.mapValues(globEntries('./src/**/vue/*.js'), entry => [entry, 'webpack-hot-middleware/client?reload=true']);
}

module.exports = {
  entry: entries,
  output: {
    path: '/', ///no real path is required, just pass "/"
    publicPath: '/vue',
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            scss: 'vue-style-loader!css-loader!sass-loader',
            sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
          },
          // other vue-loader options go here
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          query: {
            presets: ['es2015'],
            plugins: ['transform-runtime'],
          },
        },
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]',
        },
      },
    ],
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.esm.js',
    },
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(), // Enable HMR
    new webpack.NoEmitOnErrorsPlugin(),
  ],
  performance: {
    hints: false,
  },
  devtool: '#eval-source-map',
};

if (env === 'staging' || env === 'production') {
  //module.exports.devtool = env === 'staging' ? '#source-map' : false;
  module.exports.devtool = '#source-map';
  module.exports.output.path = path.resolve(__dirname, './src/v1/parse/cloud/public/vue');
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: `"${env}"`,
      },
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false,
      },
    }),
    // new BabiliPlugin(),
    new webpack.LoaderOptionsPlugin({
      minimize: true,
    }),
  ]);
}

person emkman    schedule 07.08.2017    source источник
comment
Можете ли вы предоставить минимальное репо для своей конфигурации?   -  person Herrington Darkholme    schedule 11.08.2017
comment
@HerringtonDarkholme Я мог бы предоставить репо с моим package.json и моим webpack.config.js, но код, выходящий за рамки этого, был бы трудным.   -  person emkman    schedule 13.08.2017
comment
Вы используете .babelrc файл? (vue-loader будет babel-loader использовать это.) Вы можете также использовать предустановки es2016 и es2017 (или env).   -  person bzeaman    schedule 13.08.2017
comment
@bzeaman В настоящее время я не использую файл .babelrc, но я пробовал его. Насколько я понимаю, все, что можно установить в .babelrc, можно вместо этого установить в options:. Изначально я использовал предустановку env, но по умолчанию он использует latest, и тогда я все еще не могу использовать Uglify или развернуть его в старых браузерах. Попытка указать envs, для которых требуется es2015, вернет меня в то же место.   -  person emkman    schedule 13.08.2017
comment
@emkman Я добавил свой комментарий в более обширный ответ. Вы правы в том, что параметры могут быть установлены без .babelrc, но вы не предоставляете параметры при синтаксическом анализе .vue файлов, поскольку vue-loader будет использовать .babelrc по умолчанию для своего Babel конфигурация.   -  person bzeaman    schedule 14.08.2017


Ответы (2)


vue-loader обработает ваш js с помощью babel-loader (если он обнаружен) и по умолчанию использует .babelrc.

В вашей текущей настройке вы не передаете какие-либо параметры Babel, когда он используется vue-loader (это означает, что Babel не использует правил для ваших файлов Vue).

Либо создайте .babelrc, либо самостоятельно укажите js загрузчик для файлов .vue, чтобы предоставить ему параметры:

{
  test: /\.vue$/,
  loader: 'vue-loader',
  options: {
    loaders: {
      js: 'babel?presets[]=es2015' // Pass parameters as options
    }
  }
}

Предварительная установка env для Babel имеет uglify параметр, который полностью компилируется в ES5. Эта предустановка рекомендуется для поддержания вашей среды в актуальном состоянии.

// .babelrc
{
  "presets": [
    [ "env", { "uglify": true } ],
    "stage-1" // Or other presets not included with 'env' preset.
  ],
  "plugins": ["transform-runtime"]
}

Вместо использования только предустановки es2015 вы можете добавить es2016 и es2017, а также stage-4, stage-3 и т. Д., Чтобы обеспечить преобразование всего вашего кода, а не только частей ES2015.

person bzeaman    schedule 14.08.2017
comment
Вы правы, недостаток .babelrc был проблемой. Думаю, я ошибочно предположил, что вывод vue-loader затем был передан в babel-loader с использованием моих параметров веб-пакета. Я создал .babelrc, объединяющий ваш пример и примеры из github.com/vuejs-templates, и теперь это работающий. Спасибо! - person emkman; 14.08.2017

Здесь уже нет ничего плохого в ответе, но вот решение, для которого не требуется файл .babelrc. Этот ответ работает для автономного файла webpack.config.js. Я получил этот ответ, заглянув под капот библиотеки laravel-mix.

module: {
rules: [
        {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
        },
        {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: {
                loaders:{
                    js: {
                        loader: 'babel-loader',
                        options: {                
                                    cacheDirectory: true,
                                    presets: [
                                        ['env', {
                                            'modules': false,
                                            'targets': {
                                                'browsers': ['> 2%'],
                                                uglify: true
                                            }
                                        }]
                                    ],
                                    plugins: [
                                        'transform-object-rest-spread',
                                        ['transform-runtime', {
                                            'polyfill': false,
                                            'helpers': false
                                        }]
                                    ]
                                }
                        },
                    }
            }
        },
        {
            test: /\.(png|jpg|gif|svg)$/,
            loader: 'file-loader',
            options: {
                name: '[name].[ext]?[hash]'
            }
        }

    ]
},

Я потратил большую часть дня, читая все эти бесполезные блоги, опуская основную концепцию, что babel-loader должен быть прикреплен к vue-loader.

person Jed Lynch    schedule 30.03.2018
comment
Интересно. Первоначально я работал над аналогичным подходом, но так и не смог найти правильный синтаксис для передачи параметров в babel в загрузчике vue. Спасибо, что поделился. - person emkman; 31.03.2018