Чи можу я використовувати webpack для генерації CSS та JS окремо?


86

У мене є:

  1. JS-файли, які я хочу об’єднати.
  2. МЕНШЕ файлів, які я хочу скомпілювати до CSS (вирішення @imports в єдиний пакет).

Я сподівався вказати їх як два окремі входи та мати два окремі виходи (ймовірно, за допомогою витяжки text-webpack-plugin). У Webpack є всі належні плагіни / завантажувачі для компіляції, але, схоже, це не подобається поділ.

Я бачив приклади людей, які потребують своїх МЕНШИХ файлів безпосередньо від JS, наприклад require('./app.less');, ні з якої іншої причини, окрім як сказати webpack включити ці файли до набору. Це дозволяє мати лише одну точку входу, але мені це здається насправді неправильним - чому мені потрібно менше в моєму JS, коли це не має нічого спільного з моїм кодом JS?

Я спробував використовувати декілька точок входу, передаючи як запис JS, так і основний файл LESS, але при використанні декількох точок входу webpack генерує пакет, який не виконує JS під час завантаження - він об'єднує все це, але не знає що слід виконати при запуску.

Я просто неправильно використовую webpack? Чи слід запускати окремі екземпляри webpack для цих окремих модулів? Чи повинен я взагалі використовувати веб-пакет для не-JS-активів, якщо я не збираюся змішувати їх у своєму JS?


Я можу порекомендувати такий підручник medium.freecodecamp.org/…
wilo087

Відповіді:


29

Чи повинен я взагалі використовувати веб-пакет для не-JS-активів, якщо я не збираюся змішувати їх у своєму JS?

Можливо, не. Webpack, безумовно, орієнтований на js, з неявним припущенням, що те, що ви створюєте, є js-додатком. Його реалізація require()дозволяє обробляти все як модуль (включаючи частки Sass / LESS, JSON, майже все) і автоматично виконує управління вашими залежностями за вас (все, що ви requireв комплекті, і нічого іншого).

чому мені потрібно менше в моєму JS, коли це не має нічого спільного з моїм кодом JS?

Люди роблять це, оскільки вони визначають частину свого додатка (наприклад, компонент React, Backbone View) за допомогою js. Ця частина програми має CSS, який підходить до неї. Залежно від якогось зовнішнього ресурсу CSS, який побудований окремо і на який безпосередньо не посилається модуль js, він є тендітним, складнішим для роботи і може призвести до застарілих стилів і т. Д. Webpack рекомендує зберігати все модульне, тому у вас є CSS (Sass, що завгодно) часткове, що поєднується з цим компонентом js, а компонент js - require()це, щоб зробити залежність зрозумілою (вам і інструменту побудови, який ніколи не створює стилі, які вам не потрібні).

Не знаю, чи могли б ви використовувати webpack самостійно згрупувати CSS (коли на файли CSS не посилаються жодні js). Я впевнений, що ви могли б щось підключити за допомогою плагінів тощо, але не впевнений, що це можливо нестандартно. Якщо ви все-таки посилаєтесь на файли CSS з вашого js, ви можете легко об’єднати CSS в окремий файл за допомогою плагіна Extract Text, як ви сказали.


18

Окремий пакет CSS можна створити, не використовуючи require('main/less)жоден з ваших JS, але, як зазначив Брендан у першій частині своєї відповіді, Webpack не призначений для глобального пакета CSS, який буде поєднуватися з модульним JS, однак є кілька варіантів .

Перший - додати додаткову точку входу для main.less, а потім використовувати плагін Extract Text для створення набору CSS:

var webpack = require('webpack'),
    ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    entry: {
        home: [
            'js/common',
            'js/homepage'
        ],
        style: [
            'styles/main.less'
        ]
    },
    output: {
        path: 'dist',
        filename: "[name].min.js"
    },
    resolve: {
        extensions: ["", ".js"]
    },
    module: {
        loaders: [{
            test: /\.less$/,
            loader: ExtractTextPlugin.extract("style", "css", "less")
        }]
    },
    plugins: [
        new ExtractTextPlugin("[name].min.css", {
            allChunks: true
        })
    ]
};

Проблема цього методу полягає в тому, що ви також створюєте небажаний файл JS, а також пакет, у цьому прикладі: style.jsякий є лише порожнім модулем Webpack.

Інший варіант - додати основний менший файл до існуючої точки входу Webpack:

var webpack = require('webpack'),
    ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    entry: {
        home: [
            'js/common',
            'js/homepage',
            'styles/main.less'
        ],
    },
    output: {
        path: 'dist',
        filename: "[name].min.js"
    },
    resolve: {
        extensions: ["", ".js"]
    },
    module: {
        loaders: [{
            test: /\.less$/,
            loader: ExtractTextPlugin.extract("style", "css", "less")
        }]
    },
    plugins: [
        new ExtractTextPlugin("[name].min.css", {
            allChunks: true
        })
    ]
};

Це ідеально, якщо у вас є лише 1 точка входу, але якщо у вас більше, тоді конфігурація Webpack буде виглядати трохи дивно, оскільки вам доведеться довільно вибирати, до якої точки входу додати основний менший файл.


10

Для подальшого роз'яснення попередньої відповіді bdmason - схоже, бажаною конфігурацією було б створення пакета JS та CSS для кожної сторінки, наприклад:

 entry: {
        Home: ["./path/to/home.js", "./path/to/home.less"],
        About: ["./path/to/about.js", "./path/to/about.less"]
    }

А потім використовуйте [name]перемикач:

output: {
        path: "path/to/generated/bundles",
        filename: "[name].js"
    },
plugins: new ExtractTextPlugin("[name].css")

Повна конфігурація - з деякими доповненнями, не пов’язаними з питанням (насправді ми використовуємо SASS замість LESS):

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
require('babel-polyfill');

module.exports = [{
    devtool: debug ? "inline-sourcemap" : null,
    entry: {
        Home: ['babel-polyfill', "./home.js","path/to/HomeRootStyle.scss"],
        SearchResults: ['babel-polyfill', "./searchResults.js","path/to/SearchResultsRootStyle.scss"]
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
                query: {
                    presets: ['react', 'es2015'],
                    plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
                }
            },
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract("style-loader","css-raw-loader!sass-loader")
            }
        ]
    },
    output: {
        path: "./res/generated",
        filename: "[name].js"
    },
    plugins: debug ? [new ExtractTextPlugin("[name].css")] : [
        new ExtractTextPlugin("[name].css"),
        new webpack.DefinePlugin({
            'process.env':{
                'NODE_ENV': JSON.stringify('production')
            }
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress:{
                warnings: true
            }
        })
    ]
}
];

9

рішення webpack 4 з плагіном mini-css-extract

команда webpack рекомендує використовувати mini-css-extract над плагіном для вилучення тексту

це рішення дозволяє створити окремий шматок, що містить лише ваші записи css:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else if (m.name) {
    return m.name;
  } else {
    return false;
  }
}

module.exports = {
  entry: {
    foo: path.resolve(__dirname, 'src/foo'),
    bar: path.resolve(__dirname, 'src/bar'),
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        fooStyles: {
          name: 'foo',
          test: (m, c, entry = 'foo') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
        barStyles: {
          name: 'bar',
          test: (m, c, entry = 'bar') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

Ось більш надуманий приклад використання безлічі записів одного з моїх особистих проектів:

const ManifestPlugin = require('webpack-manifest-plugin')
const webpack = require('webpack')
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const VENDOR = path.join(__dirname, 'node_modules')
const LOCAL_JS = path.join(__dirname, 'app/assets/js')
const LOCAL_SCSS = path.join(__dirname, 'app/assets/scss')
const BUILD_DIR = path.join(__dirname, 'public/dist')
const EXTERNAL = path.join(__dirname, 'public/external')

function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else if (m.name) {
    return m.name;
  } else {
    return false;
  }
}

module.exports = {
  entry: {
    vendor: [
      `${VENDOR}/jquery/dist/jquery.js`,
      `${VENDOR}/codemirror/lib/codemirror.js`,
      `${VENDOR}/codemirror/mode/javascript/javascript.js`,
      `${VENDOR}/codemirror/mode/yaml/yaml.js`,
      `${VENDOR}/zeroclipboard/dist/ZeroClipboard.js`,
    ],
    app: [
      `${LOCAL_JS}/utils.js`,
      `${LOCAL_JS}/editor.js`,
      `${LOCAL_JS}/clipboard.js`,
      `${LOCAL_JS}/fixtures.js`,
      `${LOCAL_JS}/ui.js`,
      `${LOCAL_JS}/data.js`,
      `${LOCAL_JS}/application.js`,
      `${LOCAL_JS}/google.js`
    ],
    'appStyles': [
      `${EXTERNAL}/montserrat.css`,
      `${EXTERNAL}/icons.css`,
      `${VENDOR}/purecss/pure-min.css`,
      `${VENDOR}/purecss/grids-core-min.css`,
      `${VENDOR}/purecss/grids-responsive-min.css`,
      `${VENDOR}/codemirror/lib/codemirror.css`,
      `${VENDOR}/codemirror/theme/monokai.css`,
    ]
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        appStyles: {
          name: 'appStyles',
          test: (m, c, entry = 'appStyles') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  module:  {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [ 'script-loader'],
      },
      {
        test: /\.(scss|css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
        ],
      },
    ],
  },
  mode: 'development',
  resolve: {
    extensions: ['.js', '.css', '.scss']
  },
  output: {
    path: BUILD_DIR,
    filename: "[name].[chunkhash].js",
  },
  plugins: [
    new ManifestPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].css'
    }),
  ]
};

Я усвідомлюю, що такий підхід не надто модульний, але він повинен дати вам основу для побудови та є чудовою стратегією для використання веб-пакета в проектах, де ви не хочете змішувати javascript та css.

Недоліком цього підходу є те, що css-loader все ще генерує додатковий файл javascript (незалежно від того, використовуєте ви його чи ні), це нібито буде виправлено у webpack 5 .

Чи повинен я взагалі використовувати веб-пакет для не-JS-активів, якщо я не збираюся змішувати їх у своєму JS?

Я не бачу в цьому нічого поганого, але врешті-решт це залежить від вашої толерантності до управління кількома системами збірки. Для мене це здається надмірним, тому моя перевага - залишатися в екосистемі webpack.

Для отримання додаткової інформації про стратегії, описані вище, див. Https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-css-based-on-entry


це має бути відповідь за замовчуванням сьогодні
Джіона Граната

8

Так, це можливо, але, як казали інші, для цього вам знадобляться додаткові пакети (див. DevDependencies під package.json). ось зразок коду, який я використовував для компіляції завантажувального SCSS -> CSS та Bootstrap JS -> JS.

webpack.config.js:

module.exports = {
    mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
    entry: ['./src/app.js', './src/scss/app.scss'],
    output: {
    path: path.resolve(__dirname, 'lib/modules/theme/public'),
    filename: 'js/bootstrap.js'
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'css/bootstrap.css',
                        }
                    },
                    {
                        loader: 'extract-loader'
                    },
                    {
                        loader: 'css-loader?-url'
                    },
                    {
                        loader: 'postcss-loader'
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            }
        ]
    }
};

додатковий файл postcss.config.js:

module.exports = {
    plugins: {
        'autoprefixer': {}
    }
}

package.json:

{
  "main": "app.js",
  "scripts": {
    "build": "webpack",
    "start": "node app.js"
  },
  "author": "P'unk Avenue",
  "license": "MIT",
  "dependencies": {
    "bootstrap": "^4.1.3",
  },
  "devDependencies": {
    "autoprefixer": "^9.3.1",
    "css-loader": "^1.0.1",
    "exports-loader": "^0.7.0",
    "extract-loader": "^3.1.0",
    "file-loader": "^2.0.0",
    "node-sass": "^4.10.0",
    "popper.js": "^1.14.6",
    "postcss-cli": "^6.0.1",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.26.1",
    "webpack-cli": "^3.1.2"
  }
}

Дивіться підручник тут: https://florianbrinkmann.com/en/4240/sass-webpack


1

Як і інші згадані, ви можете використовувати плагін.

ExtractTextPlugin застаріло.

Ви можете використовувати рекомендовану зараз MiniCssExtractPluginконфігурацію веб-пакета:

module.exports = {
     entry: {
        home: ['index.js', 'index.less']
     },
     plugins: [
            new MiniCssExtractPlugin({
                filename: '[name].css',
            }),
     ]
}

0

Ви також можете помістити свої оператори Менше вимагати до свого файлу JS, що входить:

в body.js

// CSS
require('css/_variable.scss')
require('css/_npm.scss')
require('css/_library.scss')
require('css/_lib.scss')

Потім у веб-пакет

  entry: {
    body: [
      Path.join(__dirname, '/source/assets/javascripts/_body.js')
    ]
  },

const extractSass = new ExtractTextPlugin({
  filename: 'assets/stylesheets/all.bundle.css',
  disable: process.env.NODE_ENV === 'development',
  allChunks: true
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.