Почему нам нужно сделать три файла конфигурации Webpack

внешний интерфейс сервер JavaScript Webpack

На Zhihu мы часто видим, как студенты спрашивают: как организованы и управляются интерфейсные проекты крупных веб-сайтов, таких как BAT? Это действительно широкий круг вопросов и ответов, и я думаю, что если я хочу ответить на этот вопрос, я мог бы также начать с конфигурации Webpack.

На сегодняшний день Webpack стал одним из необходимых базовых инструментов для фронтенд-проектов, он не только широко используется для упаковки фронтенд-проектов перед релизом, но и выступает в роли локального фронтенд-сервера ресурсов и горячей замены модулей во время разработки. . ), прокси-сервер API и другие роли в сочетании с инструментами проверки кода, такими как ESLint, также могут осуществлять строгую проверку и проверку исходного кода.

Как было сказано выше, фронтенд неотделим от участия Webpack от разработки до развертывания, а Webpack имеет только один файл конфигурации по умолчанию, а именноwebpack.config.js, тогда возникает вопрос, следует ли использовать одну и ту же конфигурацию Webpack во время разработки и перед развертыванием? Ответ определенно нет Поскольку webpack.config.js — это файл JS, мы, конечно, можем написать бизнес-логику JavaScript в файле и судить, находится ли он в настоящее время в разработке (dev) или в окончательной рабочей среде, читая переменную среды. NODE_ENV (производство), но многие студенты привыкли смешивать две конфигурации в корневом каталоге. webpack.config.js, через множество разбросанных if...else для «временного» определения элемента конфигурации плагина или загрузчика, с постоянным увеличением загрузчиков и плагинов, webpack.config.js становится все более и более оригинальным со временем читабельность и ремонтопригодность кода также значительно снижаются.

В этой статье я хотел бы представить метод настройки Webpack с 3 файлами JS, который опирается на конфигурацию многих проектов с открытым исходным кодом, а также объединяет решения различных проблем, с которыми мы столкнулись при разработке.

Конфигурация, упомянутая в этой статье, основана на Webpack 2 или выше, и рекомендуется использовать версию 3.0 и выше.

Разница между средой разработки и производственной средой

среда разработки

  • NODE_ENV — это разработка
  • Включить горячую замену модуля
  • Дополнительные элементы конфигурации webpack-dev-server, элементы конфигурации API-прокси
  • Выходная исходная карта

Производственная среда

  • NODE_ENV является производством
  • Установите общие библиотеки, такие как React и jQuery, как внешние и напрямую используйте онлайн-версию CDN.
  • Исходные файлы стилей (такие как css, less, scss и т. д.) должны быть независимо извлечены в файлы css с помощью ExtractTextPlugin.
  • использовать postcss
  • Включить оптимизацию-минимизацию (например, uglify и т. д.)
  • В производственной среде средних и крупных коммерческих веб-сайтов использование console.log() категорически запрещено, поэтому его необходимо настроить для работы с babel.Remove console transform
Здесь необходимо пояснить, что, поскольку горячая замена модулей включена в среде разработки, чтобы сделать модификацию исходных файлов стилей также горячей заменой, ExtractTextPlugin не может использоваться, а вместо этого выводится с помощью JS Bundle.

Вам нужны три файла конфигурации

1. webpack.base.config.js

В базовом файле вам необходимо централизовать конфигурацию, общую для среды разработки и производства:

const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
const webpack = require('webpack');

// 配置常量
// 源代码的根目录(本地物理文件路径)
const SRC_PATH = path.resolve('./src');
// 打包后的资源根目录(本地物理文件路径)
const ASSETS_BUILD_PATH = path.resolve('./build');
// 资源根目录(可以是 CDN 上的绝对路径,或相对路径)
const ASSETS_PUBLIC_PATH = '/assets/';

module.exports = {
  context: SRC_PATH, // 设置源代码的默认根路径
  resolve: {
    extensions: ['.js', '.jsx']  // 同时支持 js 和 jsx
  },
  entry: {
    // 注意 entry 中的路径都是相对于 SRC_PATH 的路径
    vendor: './vendor',
    a: ['./entry-a'],
    b: ['./entry-b'],
    c: ['./entry-c']
  },
  output: {
    path: ASSETS_BUILD_PATH,
    publicPath: ASSETS_PUBLIC_PATH,
    filename: './[name].js'
  },
  module: {
    rules: [
      {
        enforce: 'pre',  // ESLint 优先级高于其他 JS 相关的 loader
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'eslint-loader'
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        // 建议把 babel 的运行时配置放在 .babelrc 里,从而与 eslint-loader 等共享配置
        loader: 'babel-loader'
      },
      {
        test: /\.(png|jpg|gif)$/,
        use:
        [
          {
            loader: 'url-loader',
            options:
            {
              limit: 8192,
              name: 'images/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use:
        [
          {
            loader: 'url-loader',
            options:
            {
              limit: 8192,
              mimetype: 'application/font-woff',
              name: 'fonts/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use:
        [
          {
            loader: 'file-loader',
            options:
            {
              limit: 8192,
              mimetype: 'application/font-woff',
              name: 'fonts/[name].[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    // 每次打包前,先清空原来目录中的内容
    new CleanWebpackPlugin([ASSETS_BUILD_PATH], { verbose: false }),
    // 启用 CommonChunkPlugin
    new webpack.optimize.CommonsChunkPlugin({
      names: 'vendor',
      minChunks: Infinity
    })
  ]
};

2. webpack.dev.config.js

Это конфигурация Webpack для среды разработки, унаследованная от базы:

const webpack = require('webpack');

// 读取同一目录下的 base config
const config = require('./webpack.base.config');

// 添加 webpack-dev-server 相关的配置项
config.devServer = {
  contentBase: './',
  hot: true,
  publicPath: '/assets/'
};
// 有关 Webpack 的 API 本地代理,另请参考 https://webpack.github.io/docs/webpack-dev-server.html#proxy 

config.module.rules.push(
  {
    test: /\.less$/,
    use: [
      'style-loader',
      'css-loader',
      'less-loader'
    ],
    exclude: /node_modules/
  }
);

// 真实场景中,React、jQuery 等优先走全站的 CDN,所以要放在 externals 中
config.externals = {
  react: 'React',
  'react-dom': 'ReactDOM'
};

// 添加 Sourcemap 支持
config.plugins.push(
  new webpack.SourceMapDevToolPlugin({
    filename: '[file].map',
    exclude: ['vendor.js'] // vendor 通常不需要 sourcemap
  })
);

// Hot module replacement
Object.keys(config.entry).forEach((key) => {
  // 这里有一个私有的约定,如果 entry 是一个数组,则证明它需要被 hot module replace
  if (Array.isArray(config.entry[key])) {
    config.entry[key].unshift(
      'webpack-dev-server/client?http://0.0.0.0:8080',
      'webpack/hot/only-dev-server'
    );
  }
});
config.plugins.push(
  new webpack.HotModuleReplacementPlugin()
);

module.exports = config;

3. webpack.config.js

Вот конфигурация веб-пакета для производства, также унаследованная от базы:

const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

// 读取同一目录下的 base config
const config = require('./webpack.base.config');

config.module.rules.push(
  {
    test: /\.less$/,
    use: ExtractTextPlugin.extract(
      {
        use: [
          'css-loader',
          'less-loader'
        ],
        fallback: 'style-loader'
      }
    ),
    exclude: /node_modules/
  }
);

config.plugins.push(
  // 官方文档推荐使用下面的插件确保 NODE_ENV
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
  }),
  // 启动 minify
  new webpack.LoaderOptionsPlugin({ minimize: true }),
  // 抽取 CSS 文件
  new ExtractTextPlugin({
    filename: '[name].css',
    allChunks: true,
    ignoreOrder: true
  })
);

module.exports = config;

Теперь в папке вашего проекта должно быть три файла конфигурации Webpack:

  • webpack.base.config.js
  • webpack.dev.config.js
  • webpack.config.js

Наконец, вам также необходимоpackage.jsonДобавьте соответствующую конфигурацию:

{
  ...
  "scripts": {
    "build": "webpack --optimize-minimize",
    "dev": "webpack-dev-server --config webpack.dev.config.js",
    "start": "npm run dev" // 或添加你自己的 start 逻辑
  },
  ...
}

И много проектов, когда в среде разработки вам нужно использовать npm run dev для запуска, но в производственной среде используйте npm run build для публикации.

Не по теме, в реальных сценариях мы не будем использовать webpack-dev-server напрямую, а будем использовать экспресс +webpack/webpack-dev-middleware, способ настройки точно такой же, как описано выше.


О колонке

Если вам понравилась эта статья, пожалуйста, подпишитесь на мою колонку«Внешний нулевой стек», давайте вместе поговорим о фронтенд-технологиях и фронтенд-инжиниринге.

Об авторе

Henry, работал в научно-исследовательском центре Alibaba в Нанкине, начал изучать компьютерное программирование в возрасте 10 лет и выиграл первый приз Молодежных информационных олимпиад в Цзянсу летом в старшей школе. В 2000 году начал самостоятельно изучать JavaScript и создание веб-страниц, а с 2006 года официально начал заниматься фронтенд-разработкой, занимается этим уже более 10 лет. До прихода в Alibaba он был менеджером по продуктам интеллектуальных транспортных больших данных в научно-исследовательском институте SAP China.

Гитхаб:MagicCube (Henry Li)