web-dev-qa-db-ja.com

webpackを使用してCSSとJSを別々に生成できますか?

私は持っています:

  1. バンドルしたいJSファイル。
  2. CSSにコンパイルする(@importsを単一のバンドルに解決する)LESSファイル。

私はこれらを2つの別々の入力として指定し、2つの別々の出力を持つことを望んでいました(おそらくextract-text-webpack-pluginを介して)。 Webpackにはコンパイルを行うための適切なプラグイン/ローダーがすべて備わっていますが、分離が好きではないようです。

require('./app.less');など、JSから直接LESSファイルを必要とする人々の例を見てきましたが、これらのファイルをバンドルに含めるようwebpackに指示する以外の理由はありません。これにより、エントリポイントを1つだけにすることができますが、それは本当に間違っているようです。JSコードとは関係ないのに、なぜJSにLESSが必要なのでしょうか。

複数のエントリポイントを使用して、エントリJSとメインLESSファイルの両方を渡そうとしましたが、複数のエントリポイントを使用すると、webpackはロード時にJSを実行しないバンドルを生成します-すべてをバンドルしますが、それを知りません起動時に実行されるべきもの。

Webpackを間違って使用していますか?これらの個別のモジュールに対してwebpackの個別のインスタンスを実行する必要がありますか? JSに混在させない場合、非JSアセットにwebpackを使用する必要がありますか?

54
Brent Traut

JSに混在させない場合、非JSアセットにwebpackを使用する必要がありますか?

そうでないかもしれない。 Webpackは間違いなくjs中心であり、あなたが構築しているのはjsアプリケーションであるという暗黙の仮定です。 require()の実装により、すべてをモジュール(Sass/LESSパーシャル、JSONなど)として扱うことができ、依存関係管理が自動的に行われます(すべてrequireがバンドルされ、何もありません)。

jSコードとは何の関係もないのに、JSにLESSが必要なのはなぜですか?

これは、jsでアプリケーションの一部(Reactコンポーネント、バックボーンビュー)を定義しているためです。アプリケーションのその部分には、それに付随するCSSがあります。個別に構築され、jsモジュールから直接参照されない外部CSSリソースによっては、壊れやすく、操作が難しく、スタイルが古くなるなどの原因になる可能性があります。Webpackでは、すべてをモジュール化することをお勧めします。 (Sass、とにかく)そのjsコンポーネントに付随するパーシャル、およびjsコンポーネントrequire()sにより、依存関係が明確になります(あなたと、不要なスタイルをビルドしないビルドツール)。

CSSを単独でバンドルするためにwebpackを使用できるかどうかはわかりません(CSSファイルがどのjsからも参照されていない場合)。プラグインなどで何かを接続できると確信していますが、すぐに使用できるかどうかはわかりません。 jsからCSSファイルを参照する場合、言うように、CSSをExtract Textプラグインを使用して別のファイルに簡単にバンドルできます。

21
Brendan Gannon

JSでrequire('main/less)を使用せずに別のCSSバンドルを生成できますが、Brendanが回答の最初の部分で指摘したように、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モジュールです。

もう1つのオプションは、メインのlessファイルを既存の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構成は少し奇妙に見えます。

15
bdmason

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")

完全な構成-質問に関連しない追加がいくつかあります(実際にはLESSではなくSASSを使用しています)。

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
            }
        })
    ]
}
];
7
Gilad Barner

はい、これは可能ですが、他の人が言ったように、そうするには追加のパッケージが必要です(package.jsonのdevDependenciesを参照)。 bootstrap 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

3
geochanto