Конфигурация упаковки страницы файла с несколькими записями webpack

внешний интерфейс регулярное выражение Webpack

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


Ручная настройка

Одностраничные приложения и многостраничные приложенияwebpackНа самом деле, большинство файлов конфигурации все те же, но конфигурация нескольких страниц должна учитывать несколько страниц на основе одностраничной конфигурации.loader,output,pluginsВ основном их не нужно изменять, а файлы ввода, которые необходимо изменить, обычно являются файлами ввода.entry, если вы использовалиcssплагин стиляextract-text-webpack-plugin, плагин автоматического шаблонаhtml-webpack-pluginЕсли да, то требуется дополнительная переписывание этих двух плагинов.В большинстве случаев нам нужно изменить только эти три места, поэтому в этой статье будет кратко рассказано только об этих трех местах.Есть и другие места, которые нужно изменить , просто обратитесь к этим трем позициям.

Пример каталога файлов выглядит следующим образом:

1

entry

Конфигурация входа одностраничного приложения обычно выглядит следующим образом:

entry: resolve(__dirname, "src/home/index.js")

Эта конфигурация должна указатьwebpackот/src/home/index.jsЭтот файл начинает поступать, и выполняется ряд процессов упаковки и компиляции.

Если это многостраничное приложение, требуется несколько входных файлов, например:

entry: {
  home: resolve(__dirname, "src/home/index.js"),
  about: resolve(__dirname, "src/about/index.js")
}

Таким образом, весь проект имеет два входа.homeиabout

extract-text-webpack-plugin

extract-text-webpack-pluginПлагин предназначен в основном для извлеченияcssстили, предотвращая упаковку стилей вjsвызвать нарушение загрузки стиля страницы илиjsЕсли размер сценария слишком велик, в одностраничной программе этот плагин обычно используется следующим образом:

plugins: [
	new ExtractTextPlugin('style.[contenthash].css')
]

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

plugins: [
	new ExtractTextPlugin('home/[name].[contenthash].css'),
	new ExtractTextPlugin('about/[name].[contenthash].css')
]

В дополнение к этому следует отметить, что каждая страница нуждается только в своемcssстиль, теоретически поставить другие страницыcssМожно конечно упаковать файл стилей в свою страницу, но это явно неразумно.Это только увеличит избыточный код, а также может привести к таким проблемам, как непредсказуемое покрытие стиля.Поэтому необходимоloaderИзмените конфигурацию:

{
    test: /\.css$/,
    loader: 'style!css!autoprefixer'
},
{
    test: /\.scss$/,
    loaders: [
      'style',
      'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
      'sass',
      'autoprefixer'
    ]
},

Приведенная выше конфигурация скомпилирует всеcssфайлы в тот же файл, все, что нам нужно сделать, это поместить этиcssотдельно, каждая страница имеет свой отдельныйcssфайл стиля:

// 为每个页面定义一个 ExtractTextPlugin
const homeExtractCss = new ExtractTextPlugin('home/[name].[contenthash].css')
const aboutExtractCss = new ExtractTextPlugin('about/[name].[contenthash].css')
// ...
module: {
    rules: [
      // 每个页面的 ExtractTextPlugin 只处理这个页面的样式文件
	  {
        test: /src(\\|\/)home(\\|\/)css(\\|\/).*\.(css|scss)$/,
        use: homePageExtractCss.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'postcss-loader', 'sass-loader']
        })
      },
      {
        test: /src(\\|\/)about(\\|\/)css(\\|\/).*\.(css|scss)$/,
        use: salePersonalCenterExtractCss.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'postcss-loader', 'sass-loader']
        })
      }
	]
}
// ...
// 每个页面都有各自的 ExtractTextPlugin,所以需要都声明一遍
plugins: [
    homeExtractCss,
    aboutExtractCss
]

html-webpack-plugin

html-webpack-pluginИспользование плагинов в одностраничных и многостраничных приложенияхwebpackКонфигурация не имеет значения

new HtmlWebpackPlugin({
   filename: 'home/home.html',
   template: 'src/home/html/index.html',
   inject: true,
   minify: {
       removeComments: true,
       collapseWhitespace: true
   }
 })
 new HtmlWebpackPlugin({
   filename: 'about/about.html',
   template: 'src/about/html/index.html',
   inject: true,
   minify: {
       removeComments: true,
       collapseWhitespace: true
   }
 })

Если страниц несколько, вы можете выполнить описанную выше настройку на каждой странице.


Автоматическая конфигурация

Приведенный выше код конфигурации уже может удовлетворить потребности многостраничной разработки, но выглядит несколько прискорбно, то есть каждый раз при добавлении страницы ее нужно снова обновлятьentry,extract-text-webpack-plugin,HtmlWebpackPluginконфигурации, хотя дело всего в нескольких строчках кода, и в принципе скопировать и вставить несложно, но ведь как бы ни был мал код, его все равно нужно задавать, а мест много что нужно изменить, что можно пропустить в спешке, если это можно сделать раз и навсегда, Напишите код один раз, и вам не нужно будет спрашивать, добавляете ли вы или удаляете страницы в дальнейшем.

Небольшое наблюдение за этим каталогом показывает, что структура каталогов на самом деле очень регулярна:

1

Каждая страницаsrc/Папка в каталоге.В этой папке есть два подкаталога, в которых соответственно хранятся шаблоны этой страницы.html, файл стиляcss, и входной файлindex.js

Поскольку существуют правила, должна существовать возможность программирования кода.Если следовать этому правилу, каждая страница./srcВ следующем каталоге имя каталога является именем страницы, и структура в этом каталоге такая же, тогда вы можете получить все имена страниц с помощью общего метода (например,home,about), пример этого универсального метода выглядит следующим образом:

function getEntry () {
  let globPath = 'src/**/html/*.html'
  // (\/|\\\\) 这种写法是为了兼容 windows和 mac系统目录路径的不同写法
  let pathDir = 'src(\/|\\\\)(.*?)(\/|\\\\)html'
  let files = glob.sync(globPath)
  let dirname, entries = []
  for (let i = 0; i < files.length; i++) {
    dirname = path.dirname(files[i])
    entries.push(dirname.replace(new RegExp('^' + pathDir), '$2'))
  }
  return entries
}

с помощьюglobэта библиотека, траверс.src/В каталоге есть это правилоsrc/**/html/*.htmlподкаталог, имя этого подкаталога получается путем обычного сопоставления

Получите все имена страниц, это легко сделать.

entry

// entry: resolve(__dirname, "src/home/index.js")
// 改为
entry: addEntry()
//...
function addEntry () {
  let entryObj = {}
  getEntry().forEach(item => {
    entryObj[item] = resolve(__dirname, 'src', item, 'index.js')
  })
  return entryObj
}

extract-text-webpack-plugin

// plugins: [
	// new ExtractTextPlugin('home/[name].[contenthash].css'),
	// new ExtractTextPlugin('about/[name].[contenthash].css')
//]
// 改为
const pageExtractCssArray = []
getEntry().forEach(item => {
  pageExtractCssArray.push(new ExtractTextPlugin(item + '/[name].[contenthash].css'))
})
// ...
plugins: [...pageExtractCssArray]

module.rulesдва стиляloadersУдалите его и добавьте вместо этого динамически:

getEntry().forEach((item, i) => {
  webpackconfig.module.rules.push({
    test: new RegExp('src' + '(\\\\|\/)' + item + '(\\\\|\/)' + 'css' + '(\\\\|\/)' + '.*\.(css|scss)$'),
    use: pageExtractCssArray[i].extract({
      fallback: 'style-loader',
      use: ['css-loader', 'postcss-loader', 'sass-loader']
    })
  })
})
// ...
module.exports = webpackconfig

html-webpack-plugin

pluginsбез ручной инициализацииhtml-webpack-plugin, вместо этого добавьте динамически:

getEntry().forEach(pathname => {
  let conf = {
    filename: path.join(pathname, pathname) + '.html',
    template: path.join(__dirname, 'src', pathname, 'html', 'index.html')
  }
  webpackconfig.plugins.push(new HtmlWebpackPlugin(conf))
})
// ...
module.exports = webpackconfig

После выполнения вышеуказанной модификации, независимо от того, добавляете ли вы или удаляете страницы в проекте, вам не нужноwebpackКонфигурация была изменена вручную.Хотя поначалу кажется, что этот код динамической автоматической конфигурации становится все более и более сложным, в конечном итоге это, безусловно, хорошая практика раз и навсегда.

Кроме того, если структура каталогов вашего проекта отличается от структуры каталогов моего примера, вам необходимо внести небольшие изменения в код в соответствии с вашей собственной структурой каталогов, но общее решение проблемы такое же, простое. для поддержания проекта, структура каталогов должна быть дисциплинированной.