Tôi có thể sử dụng webpack để tạo CSS và JS riêng biệt không?


86

Tôi có:

  1. Các tệp JS mà tôi muốn nhóm.
  2. ÍT Tệp mà tôi muốn biên dịch thành CSS (phân giải @imports thành một gói duy nhất).

Tôi đã hy vọng chỉ định đây là hai đầu vào riêng biệt và có hai đầu ra riêng biệt (có thể thông qua extract-text-webpack-plugin). Webpack có tất cả các plugin / bộ nạp thích hợp để biên dịch, nhưng có vẻ như nó không thích sự tách biệt.

Tôi đã thấy các ví dụ về những người yêu cầu tệp LESS của họ trực tiếp từ JS, chẳng hạn như require('./app.less');không vì lý do gì khác ngoài việc yêu cầu webpack đưa các tệp đó vào gói. Điều này cho phép bạn chỉ có một điểm vào duy nhất, nhưng nó thực sự sai đối với tôi - tại sao tôi lại yêu cầu LESS trong JS của mình khi nó không liên quan gì đến mã JS của tôi?

Tôi đã thử sử dụng nhiều điểm nhập, đưa cả JS mục nhập và tệp LESS chính vào, nhưng khi sử dụng nhiều điểm nhập, webpack tạo ra một gói không thực thi JS khi tải - gói tất cả, nhưng tôi không biết những gì nên được thực thi khi khởi động.

Tôi chỉ sử dụng webpack sai? Tôi có nên chạy các phiên bản webpack riêng biệt cho các mô-đun riêng biệt này không? Tôi thậm chí có nên sử dụng webpack cho các nội dung không phải JS nếu tôi không kết hợp chúng vào JS của mình không?


Tôi có thể giới thiệu các hướng dẫn sau đây medium.freecodecamp.org/...
wilo087

Câu trả lời:


29

Tôi thậm chí có nên sử dụng webpack cho các nội dung không phải JS nếu tôi không kết hợp chúng vào JS của mình không?

Có thể không. Webpack chắc chắn lấy js làm trung tâm, với giả định ngầm rằng thứ bạn đang xây dựng là một ứng dụng js. Việc triển khai nó require()cho phép bạn coi mọi thứ như một mô-đun (bao gồm cả các phân đoạn Sass / LESS, JSON, khá nhiều thứ) và tự động thực hiện quản lý phụ thuộc cho bạn (mọi thứ mà bạn requiređược đóng gói và không có gì khác).

tại sao tôi yêu cầu LESS trong JS của tôi khi nó không liên quan gì đến mã JS của tôi?

Mọi người làm điều này bởi vì họ đang xác định một phần ứng dụng của họ (ví dụ: một thành phần React, một Backbone View) bằng js. Phần ứng dụng đó có CSS ​​đi kèm với nó. Việc phụ thuộc vào một số tài nguyên CSS bên ngoài được xây dựng riêng biệt và không được tham chiếu trực tiếp từ mô-đun js sẽ dễ hỏng, khó làm việc hơn và có thể dẫn đến việc các kiểu lỗi thời, v.v. Webpack khuyến khích bạn giữ mọi thứ theo mô-đun, vì vậy bạn có CSS (Sass, bất cứ điều gì) một phần đi kèm với thành phần js đó và thành phần js require()đó để làm rõ ràng sự phụ thuộc (với bạn và với công cụ xây dựng, công cụ không bao giờ xây dựng các kiểu bạn không cần).

Tôi không biết liệu bạn có thể sử dụng webpack để tự gói CSS không (khi các tệp CSS không được tham chiếu từ bất kỳ js nào). Tôi chắc chắn rằng bạn có thể kết nối một cái gì đó với các plugin, v.v., nhưng không chắc nó có thể ra khỏi hộp. Nếu bạn tham chiếu các tệp CSS từ js của mình, bạn có thể dễ dàng nhóm CSS thành một tệp riêng biệt với plugin Extract Text, như bạn nói.


18

Một gói CSS riêng biệt có thể được tạo mà không cần sử dụng require('main/less)bất kỳ JS nào của bạn, nhưng như Brendan đã chỉ ra trong phần đầu tiên của câu trả lời của mình, Webpack không được thiết kế cho một gói CSS toàn cầu đi cùng với JS mô-đun, tuy nhiên có một số tùy chọn .

Đầu tiên là thêm một điểm nhập bổ sung cho main.less, sau đó sử dụng plugin Trích xuất Văn bản để tạo gói 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
        })
    ]
};

Vấn đề với phương pháp này là bạn cũng tạo tệp JS không mong muốn cũng như gói, trong ví dụ này: style.jsđó chỉ là một mô-đun Webpack trống.

Một tùy chọn khác là thêm tệp chính ít hơn vào điểm nhập Webpack hiện có:

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

Điều này là lý tưởng nếu bạn chỉ có 1 điểm nhập, nhưng nếu bạn có nhiều hơn, thì cấu hình Webpack của bạn sẽ trông hơi kỳ lạ vì bạn sẽ phải tùy ý chọn điểm nhập nào để thêm tệp chính ít hơn vào.


10

Để làm rõ thêm câu trả lời trước đây của bdmason - có vẻ như cấu hình mong muốn sẽ là tạo một gói JS và CSS cho mỗi trang, như sau:

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

Và sau đó sử dụng công [name]tắc:

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

Cấu hình đầy đủ - với một số bổ sung không được kết nối với câu hỏi (chúng tôi thực sự đang sử dụng SASS thay vì 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

giải pháp webpack 4 với plugin mini-css-extract

nhóm webpack khuyên bạn nên sử dụng mini-css-extract trên plugin trích xuất văn bản

giải pháp này cho phép bạn tạo một đoạn riêng chỉ chứa các mục css của bạn:

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'],
      },
    ],
  },
};

Đây là một ví dụ có nội dung hơn sử dụng nhiều mục nhập từ một trong những dự án cá nhân của tôi:

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'
    }),
  ]
};

Tôi nhận thấy cách tiếp cận này không mang tính mô-đun cho lắm, nhưng nó sẽ cung cấp cho bạn một nền tảng để xây dựng và là một chiến lược tuyệt vời để áp dụng webpack trong các dự án mà bạn không muốn kết hợp javascript và css.

Nhược điểm của phương pháp này là css-loader vẫn tạo ra một tệp javascript bổ sung (cho dù bạn có chọn sử dụng nó hay không), điều này được cho là sẽ được khắc phục trong webpack 5 .

Tôi thậm chí có nên sử dụng webpack cho các nội dung không phải JS nếu tôi không kết hợp chúng vào JS của mình không?

Tôi không thấy có gì sai với điều này nhưng cuối cùng nó phụ thuộc vào khả năng chịu đựng của bạn đối với việc quản lý nhiều hệ thống xây dựng. Đối với tôi, điều này giống như quá mức cần thiết, vì vậy sở thích của tôi là duy trì trong hệ sinh thái webpack.

Để biết thêm thông tin về các chiến lược được nêu ở trên, vui lòng xem https://github.com/webpack-contrib/mini-css-extract-plugin#extract-css-based-on-entry


đây sẽ là câu trả lời mặc định hôm nay
Giona Granata

8

Có, điều này là có thể nhưng giống như những người khác đã nói, bạn sẽ cần các gói bổ sung để làm như vậy (xem devDependencies trong package.json). đây là mã mẫu mà tôi đã sử dụng để biên dịch bootstrap SCSS -> CSS và 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'
                    }
                ]
            }
        ]
    }
};

tệp postcss.config.js bổ sung:

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

Xem hướng dẫn tại đây: https://florianbrinkmann.com/en/4240/sass-webpack


1

Giống như những người khác đã đề cập, bạn có thể sử dụng một plugin.

ExtractTextPlugin không được dùng nữa.

Bạn có thể sử dụng MiniCssExtractPlugincấu hình webpack hiện được đề xuất :

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

0

Bạn cũng có thể đặt câu lệnh Ít yêu cầu hơn trong tệp JS mục nhập của mình:

trong body.js

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

Sau đó, trong webpack

  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
})
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.