Функция создания скинов Webpack, многотематическое/цветовое решение для упаковки

внешний интерфейс JavaScript CSS Webpack
Функция создания скинов Webpack, многотематическое/цветовое решение для упаковки

цветовая гамма

В этой статье в основном подробно рассказывается, как использоватьwebpack, упаковать несколько наборов решений по разным темам и проблемам, встречающимся на практике.

причина

Прежде всего, кратко представим, что такое мультитема, так называемое мультисетовое сопоставление темы/цвета — это наша очень распространенная функция скиннинга. Изменение кожи - это просто изменениеcss. Это общий вопрос, пожалуйста, обратитесь к конкретной практикеменьше практики скиннинга. В этой статье мы не будем вдаваться в подробности.
Как правило, мы будем заимствовать файлы стилей для достижения многотематичности.gulp,gruntЭтот инструмент сборки строит. Однако при этом есть огромная проблема, заключающаяся в том, что это очень неудобно. Поскольку мы использовалиwebpackУпаковка, зачем использовать другие инструменты сборки?
Кроме того, существует огромный недостаток, заключающийся в том, что css, созданный с помощью других инструментов сборки, не может поддерживаться.scopeфункциональный. Это смертельно. Итак, как использовать Как насчет веб-пакета для сборки?

Главная идея

создать некоторые<theme>.lessфайл, используяwebpackчитатьthemesФайлы стилей в каталоге, выводимые после компиляции<theme>.css. И только файл темы по умолчанию упоминается при его первой загрузке, а другие могут быть введены при переключении.
Итак, нам просто нужно решить проблему компиляции нескольких наборов выходных данных css и недопущения внедрения css в html.

Решить проблему компиляции нескольких наборов вывода css

  • Создатьинициализированный проектЭтот проект начинается сreactProject в качестве примера, прекомпилированный язык используетless. Вы можете выбрать, как вам нравится.Начальная конфигурация. после этогоlessПод папкой создайте новуюthemesкаталог и несколько<theme>.less.

    Структура каталогов

    После сборки импортируйте все файлыindex.jsсередина,webpackЭто поможет вам скомпилировать и вывести их вместе. В основном,extract-text-webpack-pluginМожет помочь нам извлечь файлы стилей, но поможет нам поместить их все в один файл.
    Исправлятьindex.js.
    import './less/index.less';
    + import './less/themes/green.less';
    + import './less/themes/red.less';
    + import './less/themes/yellow.less';
    

Затем скомпилируйте его, и вы обнаружите, что все стили перемешаны.

смешанный стиль


Ссылаясь на документацию, нам нужно объявить несколько разExtractTextPlugin, чтобы достичь цели вывода разных тем в разные файлы. Здесь я использую,loaderизincludeа такжеexcludeпараметр. Исключите другие стили в стиле по умолчанию, а затем упакуйте стили каждой темы отдельно.
Окончательные изменения кода следующие:

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 { STYLE_DEBUG } = process.env;
+ // 主题路径
+ const THEME_PATH = './src/less/themes';

const extractLess = new ExtractTextPlugin('style.[hash].css');

+ const styleLoaders = [{ loader: 'css-loader' }, { loader: 'less-loader' }];

+ const resolveToThemeStaticPath = fileName => path.resolve(THEME_PATH, fileName);
+ const themeFileNameSet = fs.readdirSync(path.resolve(THEME_PATH));
+ const themePaths = themeFileNameSet.map(resolveToThemeStaticPath);
+ const getThemeName = fileName => `theme-${path.basename(fileName, path.extname(fileName))}`;

+ // 全部 ExtractLessS 的集合
+ const themesExtractLessSet = themeFileNameSet.map(fileName => new ExtractTextPlugin(`${getThemeName(fileName)}.css`))
+ // 主题 Loader 的集合
+ const themeLoaderSet = themeFileNameSet.map((fileName, index) => {
+   return {
+     test: /\.(less|css)$/,
+     include: resolveToThemeStaticPath(fileName),
+     loader: themesExtractLessSet[index].extract({
+       use: styleLoaders
+     })
+   }
+ });


//
//..... 这里省略了
//

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          'transform-loader?brfs', // Use browserify transforms as webpack-loader.
          'babel-loader?babelrc'
        ],
        exclude: /node_modules/
      },
      {
        test: /\.(less|css)$/,
        exclude: themePaths,
        loader: extractLess.extract({
-          use: [
-            {
-              loader: 'css-loader',
-            }, {
-              loader: 'less-loader'
-            }
-          ],  
+          use: styleLoaders,
          // use style-loader in development
          fallback: 'style-loader?{attrs:{prop: "value"}}'
        })
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader'
          }
        ]
      },
+      ...themeLoaderSet
    ]
  },
  plugins: [
    extractLess,
+    ...themesExtractLessSet,
    new webpack.NamedModulesPlugin(),
    new HtmlwebpackPlugin({
      title: 'webpack 多主题打包演示',
      template: 'src/index.html',
      inject: true
    })
  ],
  devtool: STYLE_DEBUG === 'SOURCE' && 'source-map'
};

После внесения вышеуказанных изменений файл стиля может нормально выводиться.

первая сборка

Подробные изменения кодаВот и есть подробные заметки.

Не позволяйте css внедряться в html

После этого, хотяwebpackФайл стиля можно нормально скомпилировать, но есть фатальная проблема. давайте посмотрим на настоящее<head/>

<head>
  <meta charset="UTF-8" >
  <title>webpack 多主题打包演示页面</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge" >
  <meta name="viewport" content="width=device-width, initial-scale=1.0" >
  <link rel="stylesheet" type="text/css" href="/resources/loading.css" >
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css" />
  <script type="text/javascript" src="//cdn.staticfile.org/babel-standalone/6.24.0/babel.min.js"></script>
  <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default|gated,Array.prototype.includes"></script>
<link href="/style.984c33e9f2d50d6db720.css" rel="stylesheet"><link href="/theme-green.css" rel="stylesheet"><link href="/theme-red.css" rel="stylesheet"><link href="/theme-yellow.css" rel="stylesheet"></head>

Мы обнаружили, что не только вводилиstyle.cssОдновременно вводят всеtheme.css. Это явно не то, чего мы хотим. Так есть ли способ избавиться от избыточных тем?

Способ 1 (не рекомендуется)

использоватьnodeнаписать скрипт, который читаетhtml, затем удалите. Это противоречит нашему первоначальному замыслу в начале и по-прежнему зависит от других внешних сил.

Способ второй

extract-text-webpack-pluginпредоставилexcludeChunksметод, который можно использовать для исключенияentry. Таким образом, мы можем поместить все файлы стилей,themes.jsа затем добавить в записьthemes. повторное использованиеexcludeChunksПросто исключите это.

  • удалятьindex.jsссылки на стиль в .

    // style
    import './less/index.less';
    - import './less/themes/green.less';
    - import './less/themes/red.less';
    - import './less/themes/yellow.less';
    
  • Создайтеthemes.js

    import './less/themes/green.less';
    import './less/themes/red.less';
    import './less/themes/yellow.less';
    
  • Исправлятьwebpack.config.js

      entry: {
        app: './src/index.js',
    +   themes: './src/themes.js'
      },
    //
    //... 省略没用的代码
    //
    
    new HtmlwebpackPlugin({
      title: 'webpack 多主题打包演示',
      template: 'src/index.html',
      inject: true,
    + excludeChunks: ['themes']
    })
    

Построить с помощью excludeChunks

Но на этот раз я нашел еще одинthemes.bundle.jsдокумент. Поэтому его нужно удалить. Исправлятьbuildсценарий.

"build": "rm -rf dist && NODE_ENV=production webpack --mode production --progress && cp -R public/* ./dist/ "
"build": "rm -rf dist && NODE_ENV=production webpack --mode production --progress && cp -R public/* ./dist/ && && rm -rf dist/themes.bundle.js"

Закончено.изменить запись,полный код

Способ третий

Однако, добавив фразуrm -rf, все еще чувствую себя немного неловко. Так что читайте внимательноextract-text-webpack-pluginПосле документации я обнаружил, что он предоставляет функцию ловушкиhtml-webpack-plugin-after-html-processing. может справитьсяhtml.HtmlWebpackHandleCssInjectPlugin.js(служба поддержкиwebpack4и другиеwebpackВерсия).
Затем используйте так:

+ const HtmlWebpackHandleCssInjectPlugin = require('./HtmlWebpackHandleCssInjectPlugin');
//... 省略没用的代码
  plugins: [
    extractLess,
    // 将所有的 themesExtractLess 加入 plugin
    ...themesExtractLessSet,
    new webpack.NamedModulesPlugin(),
    new HtmlwebpackPlugin({
      title: 'webpack 多主题打包演示',
      template: 'src/index.html',
      inject: true
+    }),
+    new HtmlWebpackHandleCssInjectPlugin({
+      filter: (filePath) => {
+        return filePath.includes('style');
+      }
+    })
+  ],

filterфункцияArray.filerИспользование было. параметрfilePathУказанный параметрlinkна этикетке[href]ценность .
Этот метод не требует никаких инструментов и ничего не удаляет. превосходно.изменить запись, полный код

Построить с крючком

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

Скриншот финального эффекта

Последнее спасибо@xiyuyizhiкоторый предоставилценные идеи.
Если в статье есть ошибки, поправьте меня. Эта статья была одновременно опубликована в моемличный блог