Javascript 我可以使用 webpack 分别生成 CSS 和 JS 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35322958/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I use webpack to generate CSS and JS separately?
提问by Brent Traut
I have:
我有:
- JS files that I want to bundle.
- LESS files that I want to compile down to CSS (resolving @imports into a single bundle).
- 我想捆绑的 JS 文件。
- 我想编译成 CSS 的 LESS 文件(将 @imports 解析为单个包)。
I was hoping to specify these as two separate inputs and have two separate outputs (likely via extract-text-webpack-plugin). Webpack has all the proper plugins/loaders to do compilation, but it doesn't seem to like the separation.
我希望将它们指定为两个单独的输入并有两个单独的输出(可能通过 extract-text-webpack-plugin)。Webpack 拥有所有合适的插件/加载器来进行编译,但它似乎不喜欢这种分离。
I've seen examples of people requiring their LESS files directly from JS, such as require('./app.less');
, for no other reason than to tell webpack to include those files into the bundle. This allows you to only have a single entry point, but it seems really wrong to me -- why would I require LESS in my JS when it has nothing to do with my JS code?
我见过一些人直接从 JS 中要求 LESS 文件的例子,例如require('./app.less');
,除了告诉 webpack 将这些文件包含在包中之外别无他法。这允许你只有一个入口点,但对我来说似乎真的错了——为什么我需要在我的 JS 中使用 LESS,因为它与我的 JS 代码无关?
I tried using multiple entry points, handing both the entry JS and main LESS file in, but when using multiple entry points, webpack generates a bundle that doesn't execute the JS on load -- it bundles it all, but doesn't know what should be executed on startup.
我尝试使用多个入口点,同时处理入口 JS 和主 LESS 文件,但是当使用多个入口点时,webpack 会生成一个不会在加载时执行 JS 的包——它捆绑了所有内容,但不知道启动时应该执行什么。
Am I just using webpack wrong? Should I run separate instances of webpack for these separate modules? Should I even be using webpack for non-JS assets if I'm not going to mix them into my JS?
我只是使用 webpack 错了吗?我应该为这些单独的模块运行单独的 webpack 实例吗?如果我不打算将它们混合到我的 JS 中,我什至应该将 webpack 用于非 JS 资产吗?
采纳答案by Brendan Gannon
Should I even be using webpack for non-JS assets if I'm not going to mix them into my JS?
如果我不打算将它们混合到我的 JS 中,我什至应该将 webpack 用于非 JS 资产吗?
Maybe not. Webpack is definitely js-centric, with the implicit assumption that what you're building is a js application. Its implementation of require()
allows you to treat everything as a module (including Sass/LESS partials, JSON, pretty much anything), and automatically does your dependency management for you (everything that you require
is bundled, and nothing else).
也许不吧。Webpack 绝对是以 js 为中心的,隐含假设您正在构建的是一个 js 应用程序。它的实现require()
允许您将所有内容视为一个模块(包括 Sass/LESS 部分、JSON,几乎所有内容),并自动为您进行依赖项管理(您require
捆绑的所有内容,仅此而已)。
why would I require LESS in my JS when it has nothing to do with my JS code?
当它与我的 JS 代码无关时,为什么我需要在我的 JS 中使用 LESS?
People do this because they're defining a piece of their application (e.g. a React component, a Backbone View) with js. That piece of the application has CSS that goes with it. Depending on some external CSS resource that's built separately and not directly referenced from the js module is fragile, harder to work with, and can lead to styles getting out of date, etc. Webpack encourages you to keep everything modular, so you have a CSS (Sass, whatever) partial that goes with that js component, and the js component require()
s it to make the dependency clear (to you and to the build tool, which never builds styles you don't need).
人们这样做是因为他们正在用 js 定义他们的应用程序的一部分(例如一个 React 组件、一个主干视图)。应用程序的那部分具有与之配套的 CSS。依赖于一些单独构建而不直接从 js 模块引用的外部 CSS 资源是脆弱的,更难使用,并且可能导致样式过时等。Webpack 鼓励你保持一切模块化,所以你有一个 CSS (Sass,无论如何)部分与该 js 组件一起使用,并且 js 组件require()
s 它使依赖关系清晰(对您和构建工具而言,它永远不会构建您不需要的样式)。
I don't know if you could use webpack to bundle CSS on its own (when the CSS files aren't referenced from any js). I'm sure you could wire something up with plugins, etc., but not sure it's possible out of the box. If you do reference the CSS files from your js, you can easily bundle the CSS into a separate file with the Extract Text plugin, as you say.
我不知道你是否可以使用 webpack 自己捆绑 CSS(当 CSS 文件没有从任何 js 引用时)。我确定你可以用插件等连接一些东西,但不确定它是否可以开箱即用。如果您确实从 js 中引用了 CSS 文件,则可以使用提取文本插件轻松地将 CSS 捆绑到一个单独的文件中,如您所说。
回答by bdmason
A separate CSS bundle can be generated without using require('main/less)
in any of your JS, but as Brendan pointed out in the first part of his answer Webpack isn't designed for a global CSS bundle to go alongside modular JS, however there are a couple of options.
可以在不使用require('main/less)
任何 JS 的情况下生成单独的 CSS 包,但正如 Brendan 在他的回答的第一部分中指出的那样,Webpack 并不是为与模块化 JS 一起使用的全局 CSS 包而设计的,但是有几个选项.
The first is to add an extra entry point for main.less, then use the Extract Text plugin to create the CSS bundle:
首先是为 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
})
]
};
The problem with this method is you also generate an unwanted JS file as well as the bundle, in this example: style.js
which is just an empty Webpack module.
这种方法的问题是你还生成了一个不需要的 JS 文件以及包,在这个例子中:style.js
它只是一个空的 Webpack 模块。
Another option is to add the main less file to an existing Webpack entry point:
另一种选择是将主要的 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
})
]
};
This is ideal if you have only 1 entry point, but if you have more, then your Webpack config will look a bit odd as you'll have to arbitrarily choose which entry point to add the main less file to.
如果您只有 1 个入口点,这是理想的,但如果您有更多入口点,那么您的 Webpack 配置将看起来有点奇怪,因为您必须任意选择哪个入口点来添加 mainless 文件。
回答by Gilad Barner
To further clarify bdmason's former answer - it seems the desirable configuration would be to create a JS and CSS bundle for each page, like so:
为了进一步澄清 bdmason 以前的答案 - 似乎理想的配置是为每个页面创建一个 JS 和 CSS 包,如下所示:
entry: {
Home: ["./path/to/home.js", "./path/to/home.less"],
About: ["./path/to/about.js", "./path/to/about.less"]
}
And then use the [name]
switch:
然后使用[name]
开关:
output: {
path: "path/to/generated/bundles",
filename: "[name].js"
},
plugins: new ExtractTextPlugin("[name].css")
Full configuration - with some additions not connected to the question (we're actually using SASS instead of LESS):
完整配置 - 有一些与问题无关的添加(我们实际上使用的是 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
}
})
]
}
];
回答by geochanto
Yes, this is possible but like others said you will need additional packages to do so (see devDependencies under package.json). here is the sample code that I used to compile my bootstrap SCSS --> CSS and Bootstrap JS --> JS.
是的,这是可能的,但就像其他人所说的那样,您需要额外的包才能这样做(请参阅 package.json 下的 devDependencies)。这是我用来编译 bootstrap SCSS --> CSS 和 Bootstrap JS --> JS 的示例代码。
webpack.config.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'
}
]
}
]
}
};
additional postcss.config.js file:
额外的 postcss.config.js 文件:
module.exports = {
plugins: {
'autoprefixer': {}
}
}
package.json:
包.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"
}
}
See the tutorial here: https://florianbrinkmann.com/en/4240/sass-webpack
回答by lfender6445
webpack 4 solution with mini-css-extract plugin
带有 mini-css-extract 插件的 webpack 4 解决方案
the webpack team recommends using mini-css-extract over the extract text plugin
webpack 团队建议在提取文本插件上使用 mini-css-extract
this solution allows you to create a separate chunk containing only your css entries:
此解决方案允许您创建一个单独的块,仅包含您的 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'],
},
],
},
};
Here is a more contrived example using mutliple entries from one of my personal projects:
这是一个使用我个人项目中的多个条目的更人为的示例:
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'
}),
]
};
I realize this approach is not very modular, but it should give you a foundation to build from and is an excellent strategy for adopting webpack in projects where you do not wish to inter-mix javascript and css.
我意识到这种方法不是很模块化,但它应该为您提供构建基础,并且是在您不希望混合使用 javascript 和 css 的项目中采用 webpack 的绝佳策略。
The downside to this approach is that css-loader still generates an additional javascript file (whether you choose to use it or not), this will supposedly be fixed in webpack 5.
这种方法的缺点是 css-loader 仍然会生成一个额外的 javascript 文件(无论您是否选择使用它),这应该会在 webpack 5 中修复。
Should I even be using webpack for non-JS assets if I'm not going to mix them into my JS?
如果我不打算将它们混合到我的 JS 中,我什至应该将 webpack 用于非 JS 资产吗?
I don't see anything wrong with this but ultimately it depends on your tolerance for managing multiple build systems. To me this feels like overkill, so my preference is to remain in the webpack ecosystem.
我认为这没有任何问题,但最终取决于您对管理多个构建系统的容忍度。对我来说这感觉有点矫枉过正,所以我更喜欢留在 webpack 生态系统中。
For more information on the strategies outlined above, please see https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-css-based-on-entry
有关上述策略的更多信息,请参阅https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-css-based-on-entry
回答by Repastificationer
Like others mentioned you can use a plugin.
就像其他人提到的那样,您可以使用插件。
ExtractTextPlugin
is deprecated.
ExtractTextPlugin
已弃用。
You can use the currently recommended MiniCssExtractPlugin
in your webpack configuration:
您可以MiniCssExtractPlugin
在 webpack 配置中使用当前推荐的:
module.exports = {
entry: {
home: ['index.js', 'index.less']
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
]
}
回答by Ian Warner
You can also put your Less require statements in your entry JS file also:
你也可以把你的 Less require 语句放在你的入口 JS 文件中:
in body.js
在 body.js 中
// CSS
require('css/_variable.scss')
require('css/_npm.scss')
require('css/_library.scss')
require('css/_lib.scss')
Then in webpack
然后在 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
})