웹팩을 사용하여 CSS와 JS를 별도로 생성 할 수 있습니까?


86

나는 가지고있다:

  1. 번들하려는 JS 파일.
  2. CSS로 컴파일하려는 파일이 적습니다 (@imports를 단일 번들로 해결).

나는 이것을 두 개의 개별 입력으로 지정하고 두 개의 개별 출력을 갖기를 원했습니다 (아마도 extract-text-webpack-plugin을 통해). Webpack에는 컴파일을 수행 할 수있는 모든 적절한 플러그인 / 로더가 있지만 분리를 좋아하지 않는 것 같습니다.

나는 require('./app.less');웹팩에 번들에 파일을 포함하도록 지시하는 것 외에 다른 이유없이 JS에서 직접 LESS 파일을 요구하는 사람들의 예를 보았습니다 . 이것은 당신이 하나의 진입 점만을 가질 수있게 해준다. 그러나 그것은 나에게 정말로 잘못된 것처럼 보인다. 내 JS 코드와 아무 관련이 없는데 왜 내가 JS에서 LESS를 덜 요구 할까?

여러 진입 점을 사용하여 항목 JS와 기본 LESS 파일을 모두 전달했지만 여러 진입 점을 사용할 때 webpack은로드시 JS를 실행하지 않는 번들을 생성합니다. 시작시 실행해야하는 것.

웹팩을 잘못 사용하고 있습니까? 이러한 개별 모듈에 대해 별도의 웹팩 인스턴스를 실행해야합니까? JS에 혼합하지 않을 경우 비 JS 자산에도 웹팩을 사용해야합니까?


답변:


29

JS에 혼합하지 않을 경우 비 JS 자산에도 웹팩을 사용해야합니까?

아마. Webpack은 확실히 js 중심이며, 빌드중인 것이 js 응용 프로그램이라는 암시 적 가정이 있습니다. 의 구현을 require()통해 모든 것을 모듈 (Sass / LESS 부분, JSON, 거의 모든 것 포함)으로 처리하고 자동으로 종속성 관리를 수행 할 수 있습니다 ( require번들 된 모든 것 , 다른 것은 없음).

내 JS 코드와 관련이 없는데 왜 내 JS에서 LESS가 덜 필요합니까?

사람들은 js로 애플리케이션의 일부 (예 : React 컴포넌트, Backbone View)를 정의하기 때문에이를 수행합니다. 응용 프로그램의 해당 부분에는 CSS가 있습니다. 별도로 빌드되고 js 모듈에서 직접 참조되지 않는 일부 외부 CSS 리소스에 따라 깨지기 쉽고 작업하기가 더 어렵고 스타일이 최신 상태가 될 수 있습니다. Webpack은 모든 것을 모듈 식으로 유지하도록 권장하므로 CSS가 있습니다. (Sass, 무엇이든) 해당 js 구성 요소와 함께 제공되는 부분이며 js 구성 요소 require()는 종속성을 명확하게하기 위해 (필요하지 않은 스타일을 결코 빌드하지 않는 빌드 도구)입니다.

웹팩을 사용하여 CSS를 자체적으로 번들링 할 수 있는지 모르겠습니다 (CSS 파일이 어떤 js에서도 참조되지 않는 경우). 나는 당신이 플러그인 등으로 무언가를 연결할 수 있다고 확신하지만, 그것이 상자 밖에서 가능하다는 것은 확실하지 않습니다. js에서 CSS 파일을 참조하는 경우 말했듯이 Extract Text 플러그인을 사용하여 CSS를 별도의 파일로 쉽게 묶을 수 있습니다.


18

require('main/less)JS에서 사용하지 않고 별도의 CSS 번들을 생성 할 수 있지만 Brendan이 답변의 첫 부분에서 지적했듯이 Webpack은 모듈 식 JS와 함께 사용할 전역 CSS 번들을 위해 설계되지 않았지만 몇 가지 옵션이 있습니다. .

첫 번째는 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 진입 점에 main less 파일을 추가하는 것입니다.

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

전체 구성-질문에 연결되지 않은 일부 추가 사항 포함 (실제로 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
            }
        })
    ]
}
];

9

mini-css-extract 플러그인이있는 webpack 4 솔루션

웹팩 팀은 추출 텍스트 플러그인보다 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'
    }),
  ]
};

저는이 접근 방식이 모듈식이 아니라는 것을 알고 있지만 빌드 할 기반을 제공해야하며 자바 스크립트와 CSS를 혼용하지 않으려는 프로젝트에서 웹팩을 채택하기위한 훌륭한 전략입니다.

이 접근 방식의 단점은 css-loader가 여전히 추가 javascript 파일을 생성한다는 것입니다 (사용 여부에 관계없이). 이것은 아마도 webpack 5에서 수정 될 것 입니다.

JS에 혼합하지 않을 경우 비 JS 자산에도 웹팩을 사용해야합니까?

나는 이것에 잘못된 것이 없다고 생각하지만 궁극적으로 여러 빌드 시스템을 관리하는 데 대한 관용에 달려 있습니다. 나에게 이것은 과잉처럼 느껴지므로 웹팩 생태계에 남아있는 것이 선호됩니다.

위에 설명 된 전략에 대한 자세한 내용은 https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-css-based-on-entry 를 참조 하십시오.


이 오늘 기본 응답을해야한다
Giona Granata

8

예, 가능하지만 다른 사람들이 그렇게하려면 추가 패키지가 필요하다고 말했습니다 (package.json 아래의 devDependencies 참조). 다음은 부트 스트랩 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

Less require 문을 항목 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
})
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.