Webpack4 здесь официально! Вы знали, что они называют это Легато! Есть много новых функций и улучшений. Игра Шона Т. Ларкина в Webpack 4 поднялась на 3 уровня. Вы можете прочитать об изменениях в этой статье или здесь, в git-changelog.

Короче говоря, Webpack4 на 98% быстрее. У них есть Mode, # 0CJS и разумные настройки по умолчанию. 😻 Он имеет разбиение на части как настраиваемое значение по умолчанию для различных режимов. Типы модулей представлены вместе с поддержкой .mjs и поддержкой WebAssembly. Javascript будущего уже здесь! 💥

Я перенес один базовый стартер VueJs на Webpack4, и это оказалось довольно легко. У меня было немного сбоев, потому что некоторые плагины еще не обновлены для Webpack 4. Но как только появится необходимая поддержка, портирование существующих проектов до последней версии займет несколько минут. Я начал с # 0CJS (Zero-Config JS), в котором используются режимы по умолчанию, но как только я интегрировал Vue, я добавил несколько базовых конфигураций для создания начального проекта, который включает маршрутизацию, тестирование и настраиваемый файл HTML.

Что касается кода: я использовал режимы 0-Configuration для сборок производства / разработки и использовал webpack-dev-server для целей разработки. Я добавил все статьи по теме, которые смог найти о Webpack4, в конце этой статьи, чтобы упростить процесс миграции. Каждый подзаголовок указывает на код репозитория Git, вы также можете напрямую проверить его оттуда, щелкнув заголовки.

  1. Package.json: 📁
    Мой первоначальный package.json прост. Скрипт для разработки, сборки и для webpack-dev-server. Также есть скрипты для тестирования.
{
  "name": "webpack-4-quickstart",
  "version": "1.0.0",
  "description": "> Webpack 4 tutorial: VueJs starter-kit, from 0 Conf to Production Mode",
  "main": "index.js",
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --inline --hot",
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "test": "node_modules/.bin/karma start",
    "test-grep": "node_modules/.bin/karma start --grep"
  },
  "repository": {
    "type": "git",
    "url": "git+https://https://github.com/nnupoor/webpack4vue.git"
  },
  "keywords": [],
  "author": "Neha Nupoor",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/nnupoor/webpack4vue/issues"
  },
  "homepage": "https://github.com/nnupoor/webpack4vue#readme",
  "devDependencies": {
    "autoprefixer-loader": "^3.2.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "chai": "^4.1.1",
    "cross-env": "^5.1.3",
    "css-loader": "^0.23.1",
    "extract-text-webpack-plugin": "^2.1.0", //not working currently.
    "file-loader": "^0.8.4",
    "html-webpack-plugin": "webpack-contrib/html-webpack-plugin", //is a patch right now.
    "inject-loader": "^3.0.1",
    "istanbul": "^0.4.5",
    "karma": "^1.7.0",
    "karma-chai": "^0.1.0",
    "karma-chrome-launcher": "^2.2.0",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-requirejs": "^1.1.0",
    "karma-sinon": "^1.0.5",
    "karma-webpack": "^2.0.4",
    "karma-webpack-grep": "^1.0.1",
    "mocha": "^3.5.0",
    "node-sass": "^4.5.3",
    "requirejs": "^2.3.5",
    "sass-loader": "^6.0.5",
    "sinon": "^3.2.1",
    "style-loader": "^0.14.1",
    "surge": "^0.18.0",
    "svg-sprite-generator": "0.0.7",
    "svg-sprite-loader": "^0.3.0",
    "vue-loader": "^14.1.1",
    "vue-template-compiler": "^2.5.13",
    "vue-resource": "^1.2.1",
    "vue-router": "^2.3.0",
    "webpack": "^4.0.0",
    "webpack-cli": "^2.0.8",
    "webpack-dev-server": "^3.0.0",
    "webpack-serve": "^0.1.4"
  },
  "dependencies": {
    "vue": "^2.5.13"
  }
}

2. Файл webpack.config.js: 💣
После того, как вы настроили package.json, пора настроить файл webpack.config.js. Я создал базовый файл, но его можно разделить или улучшить. Этого должно быть достаточно, чтобы вы начали.

const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const NODE_ENV = process.env.NODE_ENV;
const setPath = function(folderName) {
  return path.join(__dirname, folderName);
}
const isProd = function() {
  return (process.env.NODE_ENV === 'production') ? true : false;
}
const buildingForLocal = () => {
  return (NODE_ENV === 'development');
};
const setPublicPath = () => {
  let env = NODE_ENV;
  if (env === 'production') {
    return 'https://your-host.com/production/';
  } else if (env === 'staging') {
    return 'https://your-host.com/staging/';
  } else {
    return '/';
  }
};
const extractCSS = new ExtractTextPlugin({
  filename: "css/styles.[hash].css",//"[name].[contenthash].css",
  disable: process.env.NODE_ENV === "development"
});
const extractHTML = new HtmlWebpackPlugin({
  title: 'History Search',
  filename: 'index.html',
  inject: true,
  template: setPath('/src/tpl/tpl.ejs'),
  environment: process.env.NODE_ENV,
  isLocalBuild: buildingForLocal(),
  imgPath: (!buildingForLocal()) ? 'assets' : 'src/assets'
});
const config = {
  /**
   * You can use these too for bigger projects. For now it is 0 conf mode for me!
   */
  // entry: {
  //   build: path.join(setPath('src'), 'main.js'),
  //   vendor: path.join('setPath('src'), 'vendor.js')
  // },
  // output: {
  //   path: buildingForLocal() ? path.resolve(__dirname) : setPath('dist'), //this one sets the path to serve
  //   publicPath: setPublicPath(),
  //   filename: buildingForLocal() ? 'js/[name].js' : 'js/[name].[hash].js'
  // },
  
  optimization:{
    runtimeChunk: false,
    splitChunks: {
      chunks: "all", //Taken from https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
    }
  },
  resolveLoader: {
    modules: [setPath('node_modules')]
  },
  mode: buildingForLocal() ? 'development' : 'production',
  devServer: {
    historyApiFallback: true,
    noInfo: false
  },
  plugins: [
    extractHTML,
    // extractCSS,
    new webpack.DefinePlugin({
      'process.env': {
        isStaging: (NODE_ENV === 'development' || NODE_ENV === 'staging'),
        NODE_ENV: '"'+NODE_ENV+'"'
      }
    })
  ],
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            js: 'babel-loader'
          }
        }
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: [{
          loader: "babel-loader",
          options: { presets: ['es2015'] }
        }]
      },
      {
        test: /\.css$/,
        use: extractCSS.extract({
          fallback: "style-loader",
          use: ["css-loader", "autoprefixer-loader"]
        })
      },
      {
        test: /\.scss$/,
        use: !buildingForLocal() ?
            extractCSS.extract({
              fallback: "style-loader",
              use: ['css-loader', 'autoprefixer-loader', 'sass-loader']
            }) :
            [{
                loader: "style-loader" // creates style nodes from JS strings
              }, {
                loader: "css-loader" // translates CSS into CommonJS
              }, {
                loader: "sass-loader" // compiles Sass to CSS
              }]
      },
      {
        test: /\.svg$/,
        loader: 'svg-sprite-loader'
      },
      {
        test: /\.(png|jpg|gif)$/,
        loader: 'file-loader',
        query: {
          name: '[name].[ext]?[hash]',
          useRelativePath: buildingForLocal()
        }
      }    
    ]
  },
};
module.exports = config;

2.1 Настройка HtmlWebpackPlugin: 🍫
Для упрощения я использовал HtmlWebpackPlugin, чтобы взять шаблон .ejs и заполнить его сгенерированными пакетами js / css. HtmlWebpackPlugin официально не работает, но я пока использовал патч, предоставленный webpack.

const extractHTML = new HtmlWebpackPlugin({
  title: 'History Search',
  filename: 'index.html',
  inject: true,
  template: setPath('/src/tpl/tpl.ejs'),
  environment: process.env.NODE_ENV,
  isLocalBuild: buildingForLocal(),
  imgPath: (!buildingForLocal()) ? 'assets' : 'src/assets'
})
// Inside config object
const config = { 
. 
.
  plugins: [extractHTML],
}

2.2 Извлечение CSS с помощью ExtractTextPlugin: 🙅🏻
Затем мы берем ExtractTextPlugin и извлекаем CSS, чтобы облегчить разделение CSS. Теперь этот плагин не работает сейчас. (* Изменить: они выпустили бета-версию плагина, о которой я не знал. Шон Т. Ларкин указал на это, и я обновил код, чтобы он работал. *)

const extractCSS = new ExtractTextPlugin({
  filename: "css/styles.[hash].css",//"[name].[contenthash].css",
  disable: process.env.NODE_ENV === "development"
});
// Inside config object
const config = { 
. 
.
  plugins: [extractHTML],
}

2.3 Настройка конфигурации режима: ✋🏻
Мы также можем установить режим конфигурации веб-пакета явно в объекте конфигурации.

const config = {
.
.
  mode: buildingForLocal() ? 'development' : 'production'
}

2.4 Настройка конфигурации оптимизации: 🎯
Вы также можете настроить объект оптимизация. Такие плагины, как NoEmitOnErrorsPlugin, ModuleConcatenationPlugin, NamedModulesPlugin перемещаются в конфигурацию оптимизации, и для них установлены значения по умолчанию в зависимости от выбранного вами режима. CommonsChunkPlugin был удален, его конфигурация теперь находится внутри объекта оптимизации. Его можно настроить следующим образом:

optimization:{
    runtimeChunk: false,
    splitChunks: {
      chunks: "all", //Taken from https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
    }
  }

Одна хорошая вещь в этой миграции заключалась в том, что я смог выяснить свои ошибки, просто прочитав ошибки консоли. Я сделал много ошибок при настройке вышеуказанного параметра, и мне легко удалось настроить его правильно благодаря информативным ошибкам, которые я получал. 🧀

2.5 Настройка конфигурации devServer для webpack-dev-server: 🎢
Теперь настраиваем devServer. Я заметил одну вещь: если я установил noInfo: true, то я не получал никакой информации о порте, на котором работает мой сервер, в отличие от предыдущих версий. Чтобы прийти к каким-либо выводам, нужно вникнуть в него глубже. Пока это неправда.

devServer: {
    noInfo: false
 }

2.6 Настройка модулей: ⚓️
Ничего особенного, только старые Vue, JS, CSS, SCSS, SVG и загрузчики изображений.

module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          // postcss: [require('postcss-cssnext')()]
          // options: {
            //   extractCSS: true
            // }
          loaders: {
            js: 'babel-loader'
          }
        }
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: [{
          loader: "babel-loader",
          options: { presets: ['es2015'] }
        }]
      },
      // {
      //   test: /\.css$/,
      //   use: extractCSS.extract({
      //     fallback: "style-loader",
      //     use: ["css-loader", "autoprefixer-loader"]
      //   })
      // },
      {
        test: /\.scss$/,
        use: //!buildingForLocal() ?
            // extractCSS.extract({
            //   fallback: "style-loader",
            //   use: ['css-loader', 'autoprefixer-loader', 'sass-loader']
            // }) :
            [{
                loader: "style-loader" // creates style nodes from JS strings
              }, {
                loader: "css-loader" // translates CSS into CommonJS
              }, {
                loader: "sass-loader" // compiles Sass to CSS
              }]
      },
      {
        test: /\.svg$/,
        loader: 'svg-sprite-loader'
      },
      {
        test: /\.(png|jpg|gif)$/,
        loader: 'file-loader',
        query: {
          name: '[name].[ext]?[hash]',
          useRelativePath: buildingForLocal()
        }
      }    
    ]
  }

Если вы видите, я закомментировал функции extractCSS. Они не работали. Использование CSS в Vue для победы! 🥊 (* Изменить: сейчас работает. См. Выше. *)

Вот и все. Это базовая конфигурация / миграция для webpack 4, которую мне нужно было сделать, чтобы запустить простой проект VueJs с нуля. Я добавил базовые тесты, маршрутизацию, следил за структурой каталогов страницы, макета и компонентов.

Примечание: в приведенном выше коде я удалил несколько строк для простоты объяснения, репозиторий Git имеет весь необходимый код, чтобы любой мог начать работу с VueJs и Webpack 4. Я хочу изучить и открыть для всех обратная связь, которую вы все можете предложить.

NOTE: This code has been updated on git for webpack v4.1.1 and modules like "mini-css-extract-plugin" have been added which are released recently. Take a look at the code, if not, most of the issues with plugins have been sorted by now. Happy coding! :)


  1. Заявление о выпуске Webpack4: https://medium.com/webpack/webpack-4-released-today-6cdb994702d4
  2. Руководство по миграции Webpack4 для загрузчиков / плагинов: https://medium.com/webpack/webpack-4-migration-guide-for-plugins-loaders-20a79b927202
  3. Режимы Webpack: https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a
  4. Журналы выпуска Webpack4: https://github.com/webpack/webpack/releases
  5. Webpack4 SplitChunks: https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
  6. Webpack CommonchunksPlugin: https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
  7. Документация по Webpack: https://webpack.js.org/guides/

Если вы нашли статью полезной и знаете это, хлопайте в ладоши! Это сделало бы меня таким 😍