Принцип упаковки Webpack и базовая конфигурация

Webpack

Введение в вебпак

WebPack на самом деле является статический модульный пакет

Когда webpack обрабатывает проект, он рекурсивно строит граф зависимостей, содержащий каждый модуль, необходимый приложению, а затем объединяет все эти модули в один или несколько пакетов.

Принцип упаковки

image

  • Определите входной файл

Упаковка команд отладки

npm run dev

npm run build

packages.json

...
"scripts": {
  "dev_def": "webpack-dev-server --inline --public --config build/dev.js",
  "dev": "nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\"",
  "start": "npm run dev",
  "build": "cross-env NODE_ENV=production node build/build.js"
}
...

webpack-dev-server

Это легкий сервер.После изменения исходного кода файла страница автоматически обновляется, чтобы синхронизировать изменение со страницей.

webpack-dev-server --inline --public --config build/dev.js
  • [--inline или --inline=false] Встроенный режим: сценарии будут вставлены в пакет для обработки перезагрузки в реальном времени, а сообщения о сборке будут отображаться в консоли браузера.
module.exports = {
  //...
  devServer: {
    inline: true
  }
};
  • [--public xxx] При использовании встроенного режима и проксирования dev-сервера встроенные клиентские сценарии не всегда знают, куда подключаться. Он попытается угадать window.location на основе URL-адреса сервера, но ему нужно будет использовать его, если это не удастся.
  • [--config xxx] Указать файл конфигурации
  • [--progress] Вывести текущий прогресс на консоль.

nodemon

Он будет отслеживать файлы в проекте. Как только файлы будут изменены, Nodemon автоматически перезапустит приложение.

  • [--watch xxx] Мониторинг указанного файла или каталога
  • [--Exec xxx] выполняет указанную команду
nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\"

Это предложение означает: Используйте nodemon для мониторинга файла config/index.js.Если есть какие-либо изменения, повторно выполните команду [webpack-dev-server --inline --public --config build/dev.js]

Команда [webpack-dev-server --inline --public --config build/dev.js] имеет функцию горячего обновления для самого проекта, но при изменении файла конфигурации webpack сам dev-сервер не возьмет эффект. Использование nodemon заключается в перезапуске службы при изменении файла конфигурации webpack, что является автоматическим дополнением

cross-env

Решите сценарии для кросс-платформенной настройки и использования переменных среды, таких как сглаживание имен переменных, путей

  • cross-env NODE_ENV=production устраняет проблему установки кросс-платформенных переменных окружения

базовая конфигурация

module.exports = {
  // 入口文件
  entry: {
    app: './src/js/index.js'
  },
  // 在哪里输出它所创建的 bundles
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'     //确保文件资源能够在 http://localhost:3000 下正确访问
  },
  // 开发者工具 source-map
  devtool: 'inline-source-map',
  // 创建开发者服务器
  devServer: {
    contentBase: './dist',
    hot: true                // 热更新
  },
  plugins: [
    // 删除dist目录
    new CleanWebpackPlugin(['dist']),
    // 重新穿件html文件
    new HtmlWebpackPlugin({
      title: 'Output Management'
    }),
    // 以便更容易查看要修补(patch)的依赖
    new webpack.NamedModulesPlugin(),
    // 热更新模块
    new webpack.HotModuleReplacementPlugin()
  ],
  // 环境
  mode: "development",
  // loader配置
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  }
}

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

запись (конфигурация входного файла)

Синтаксис одиночной записи (сокращенно)

entry: './path/to/my/entry/file.js'

// 或者(对象写法)

entry: {
  main: './path/to/my/entry/file.js'
}

многостраничное приложение

entry: {
  pageOne: './src/pageOne/index.js',
  pageTwo: './src/pageTwo/index.js',
  pageThree: './src/pageThree/index.js'
}

entry:{
  vendor:[resolve('src/lib/polyfill.js'), 'vue', 'vue-router'], // 不推荐
  app: resolve('src/main.ts')
}

В версии до WebPack4 поставщик обычно добавляется как отдельная точка входа для компиляции в отдельный файл Vendor (в сочетании с CommonSchunkPlugin)

Это не рекомендуется в веб-пакете 4. Вместо этогоoptimization.splitChunksПараметры отвечают за разделение модулей поставщиков и приложений и создание отдельных файлов. Не создавайте записи для поставщиков или других вещей, которые не являются отправной точкой для выполнения.

Выход (конфигурация вывода файла)

output: {
  filename: '[name].bundle.js',
  chunkFilename: [name].min.js,
  path: path.resolve(__dirname, 'dist'),
  publicPath: '/'     //确保文件资源能够在 http://localhost:3000 下正确访问
}
  • ChunkFileName: этот параметр определяет имя не входного файла
  • путь: путь назначения для всех выходных файлов
  • publicPath: укажите каталог, на который ссылается файл ресурсов, файл после сборки и префикс пути ссылки на ресурс.

devtool (инструмент отладки: сопоставление файлов)

// dev
devtool: 'eval-source-map'

// prod
devtool: 'source-map'

Секреты ключевых слов:

ключевые слова имея в виду
eval При упаковке сгенерированный файл bundle.js и модули оборачиваются eval, за которым следует sourceUrl, указывающий на исходный файл.
source-map Эта конфигурация создаст файл .map, и файл карты будет сопоставлен с исходным файлом.При отладке файл .map используется для определения расположения исходного кода.
cheap Упаковка с низким потреблением означает, что файл карты не сохраняет информацию о позиции столбца исходного кода при упаковке, а содержит только информацию о позиции строки, поэтому это объясняет описание, стоящее за официальной картой веб-сайта (только строки).
... ...

devServer

devServer: {
  compress: true,
  port: 9000,
  hot: true,
  https: true,
  overlay: {
    warnings: false,
    errors: true
  },
  publicPath: '/platform/redapply/'
}
  • сжать: включить сжатие gzip
  • порт: номер порта
  • hot: следует ли включить функцию замены горячего модуля.
  • HTTPS: Вы можете использовать самозаписанный сертификат, также может настроить подписанный сертификат | Boolean, объект
  • Наложение: полноэкранные ошибки компиляции или предупреждения в браузере | Boolean, объект
  • publicPath: упакованный файл будет развернут по пути, соответствующему этой конфигурации.http://localhost:8080/platform/redapply/index.html

режим (указывает веб-пакету использовать встроенную оптимизацию соответственно)

// dev
mode: 'development'

// build
mode: 'production'

плагины

plugins: [
  new webpack.DefinePlugin({
    'process.env': {
       NODE_ENV: '"production"'
     }
  }),
]

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader'
      ]
    },
    {
      test: /\.(png|svg|jpg|gif)$/,
      use: [
        'file-loader'
      ]
    }
  ]
}

Общая конфигурация проекта

решать

resolve: {
  extensions: ['.js','.ts', '.vue', '.json'],
  alias: {
    '@lib': resolve('src/lib'),
    '@models': resolve('build/models'),
    '@components': resolve('src/components'),
    '@data': resolve('src/data'),
    '@': resolve('src')
  }
}
  • Расширения имени файла по умолчанию при выборе суффикса пути разбора (в свою очередь попробуйте заказать)
  • Пользовательские символы соответствуют заданному псевдониму пути

Предварительно загрузить файлы

Например, определите несколько общедоступных файлов scss. Чтобы не импортировать этот файл для каждой страницы. Мы можем установить предварительную загрузку файлов

module: {
  rules: [
    ...
    {
      test: /\.sass|scss|css$/,
      use: [
        ...
        {
          loader: 'sass-resources-loader',
          options: {
            resources: [
              path.resolve(__dirname, '../src/assets/css/vars.scss'),
              path.resolve(__dirname, '../src/assets/css/common.scss')
            ]
          }
        }
      ]
    }
  ]
}

оптимизация (элемент конфигурации оптимизации, настраиваемый при сборке)

optimization: {
    minimize: true,                         // 默认为true,效果就是压缩js代码。
    minimizer: [                            // 压缩时调用的插件
      new TerserPlugin(),
      new OptimizeCSSAssetsPlugin({})
    ],
    runtimeChunk: {                         // 默认为false,抽离出运行时公共代码块。
      name: 'manifest'
    },
    splitChunks:{
      chunks: 'all',                        // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
      minSize: 30000,                       // 生成块的最小字节数,30000
      minChunks: 1,                         // 最少被引用的次数
      maxAsyncRequests: 3,                  // 按需加载时候最大的并行请求数
      maxInitialRequests: 3,                // 一个入口最大的并行请求数
      name: true,                           // 打包的chunks的名字
      cacheGroups: {                        // 缓存配置
        common: {
          name: 'common',                   // 要缓存的 分隔出来的 chunk 名称
          chunks: 'initial',                // 必须三选一: "initial" | "all" | "async"(默认就是async) 
          priority: 11,
          enforce: true,
          reuseExistingChunk: true,         // 可设置是否重用该chunk
          test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
        },
        vendor: {                           // key 为entry中定义的 入口名称
          name: 'vendor',                   // 要缓存的 分隔出来的 chunk 名称
          chunks: 'initial',                // 必须三选一: "initial" | "all" | "async"(默认就是async) 
          priority: 10,
          enforce: true,
          reuseExistingChunk: true,         // 可设置是否重用该chunk
          test: /node_modules\/(.*)\.js/
        },
        styles: {
          name: 'styles',
          test: /\.(scss|css)$/,
          chunks: 'all',
          minChunks: 1,
          reuseExistingChunk: true,
          enforce: true
        }
      }
    }
  }

runtimeChunk

Значение по умолчанию — false, извлечение общего блока кода времени выполнения.

Что такое время выполнения (время выполнения)?

JS в браузере может вызывать API, предоставляемый браузером, например объект окна, API, связанный с DOM, и т. д. Эти интерфейсы не предоставляются движком V8, но существуют в браузере. Поэтому, проще говоря, для этих связанных внешних интерфейсов JS может вызывать их во время выполнения, а также цикл событий JS (Event Loop) и очередь событий (Callback Queue), которые называются RunTime. В некоторых местах основная библиотека core lib, используемая JS, также считается частью RunTime.

время выполнения фрагмента

Когда окружающая среда выполнения куска зависит (метод)

splitChunks

chunks

function (chunk) | string

Указывает, какие блоки будут выбраны для оптимизации.

string:

  • initial - чанк входа, не обработанный для асинхронно импортированных файлов
  • async — асинхронный фрагмент, обрабатывающий только файлы, импортированные асинхронно (личное понимание)
  • все - все куски

function:

splitChunks: {
  chunks (chunk) {
    // exclude `my-excluded-chunk`
    return chunk.name !== 'my-excluded-chunk';
  }
}

cacheGroups

Группы кеша могут наследовать и/или переопределять любые параметры splitChunks.*; чтобы отключить любые группы кеша по умолчанию, установите для этого параметра значение false.

  • Приоритет приоритета, модуль может принадлежать нескольким группам кеша и в конечном итоге будет введен в CHUNK с высоким приоритетом.
  • ReuseexistingChunk указывает на то, что вы можете использовать уже существующие блоки, то есть, если вы соответствуете уже существуют блоки, используйте существующие, больше не создавайте новый блок.
  • Установите Minsize, Minchunks, MaxinitialRequests возможность быстро создать кусок с
optimization: {
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    minChunks: 1,
    maxAsyncRequests: 3,
    maxInitialRequests: 3,
    name: true,
    cacheGroups: {
      common: {
        name: 'common',
        chunks: 'initial',
        priority: 11,
        enforce: true,
        reuseExistingChunk: true,         // 可设置是否重用该chunk
        test: /[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/
      },
      vendor: {
        name: "vendor",
        chunks: "initial",
        priority: 10,
        test: /[\/|\\]node_modules[\/|\\](.*)\.js/
      },
      styles: {
        name: 'styles',
        test: /\.(scss|css|less)$/,
        chunks: 'initial',
        minChunks: 1,
        reuseExistingChunk: true,
        enforce: true
      }
    }
  }
}

Уведомление:

Вот яма, то есть вопрос пути тестового матча Общий Интернет, чтобы увидеть, например:

...
common: {
  name: 'common',
  chunks: 'initial',
  priority: 11,
  enforce: true,
  reuseExistingChunk: true,
  test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
}
...

Существует регулярный тест на совпадение среды Linux с путем. (Например: node_modules/vue)

Но путь окна не совпадает с путем Linux, это обратная косая черта. (например: node_modules\vue)

Таким образом, мы хотим изменить обычный

/[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/

Это совместимо с обеими средами

конфигурация в проекте

Вообще говоря, для веб-пакета требуется 3 файла конфигурации.

  • webpack.base.conf.js // общедоступная конфигурация
  • webpack.dev.conf.js // Конфигурация среды разработки
  • WebPack.Prod.conf.js // Конфигурация рабочей среды

Но конфигурация, которую вы видите в нашем проекте, не совсем такая, как описанная выше.

Это потому, что: когда мы генерируем проект в скаффолдинге, мы уже интегрировали базовую конфигурацию веб-пакета.

Все они находятся под @zz/webpack-vue.

image

И только некоторые записи объекта конфигурации выставлены в нашем проекте.

image

Открытая структура элемента конфигурации немного отличается от структуры самого веб-пакета.

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

(Эта статья является общем внутренним специальным учебным учетом, контентной основой для сравнения)