有一些关于style-loader
和css-loader
的SO帖子,但尽管如此,我还没有能够找到解决我的问题的方法。
简而言之,如果在其他css
文件中导入@import
css
文件,并且导入的css
包含具有相对路径的url()
,则无法正确解析路径。
基本上,错误消息表明Webpack最终认为导入的css中的url()
路径是相对于src
(主入口点)的,而不是相对于它所导入到的css
文件的:
// css-one.scss
@import "./assets/open-iconic-master/font/css/open-iconic-bootstrap.css";
// open-iconic-bootstrap.css
@font-face {
src: url('../fonts/open-iconic.eot');
}
错误:
在./src/main.scss中出现错误(./节点模块/css-loader??ref--5-1!./节点模块/postcss-loader/src??ref--5-2!./节点模块/sass-loader/lib/loader.js??ref--5-3!./src/main.scss)
找不到模块:错误:无法解析'C:\Users...\src'**@ ./src/main.scss**(./node_modules/css-loader??ref--5-1!./node_modules/postcss-loader/src??ref--5 -2!./node_modules/sass-loader/lib/loader.js??ref--5-3!./src/main.scss)中的'../字体/打开图标. eot'在'C:\Users..\src'*@ ./src/main.scss @./src/index. js
我尝试过的方法:
- 我已经尝试在样式加载器中使用
convertToAbsoluteUrls
标志 - 我已尝试关闭所有源Map(mentioned in style-loader docs)
我的Webpack配置文件(加载程序位于底部):
const path = require('path');
const webpack = require('webpack'); // for webpack built-in plugins
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
// const WriteFilePlugin = require('write-file-webpack-plugin');
// const ManifestPlugin = require('webpack-manifest-plugin');
// const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const PATHS = {
// when using __dirname, resolve and join gives same result,
// because __dirname is absolute path to directory of this file.
// OK to use no slashes,
// both resolve and join adds platform-specific separators by default
src: path.resolve(__dirname, 'src'),
dist: path.resolve(__dirname, 'dist'),
build: path.resolve(__dirname, 'build'),
test: path.resolve(__dirname, 'test')
};
const NAMES = {
// JS FILES
index: 'index',
print: 'print',
// Chrome Extension Development
popup: 'popup',
options: 'options',
background: 'background',
contentScript: 'contentScript',
// FOLDERS
assets: 'assets',
utilities: 'utilities',
images: 'images',
fonts: 'fonts',
include: 'include'
};
const FILE_PATHS = {
// JS
indexJs: `${path.join(PATHS.src, NAMES.index)}.js`,
printJs: `${path.join(PATHS.src, NAMES.print)}.js`,
// Chrome Extension Development
popupJs: `${path.join(PATHS.src, NAMES.popup)}.js`,
optionsJs: `${path.join(PATHS.src, NAMES.options)}.js`,
backgroundJs: `${path.join(PATHS.src, NAMES.background)}.js`,
contentScriptJs: `${path.join(
PATHS.src,
NAMES.include,
NAMES.contentScript
)}.js`,
// HTML
indexHtml: `${path.join(PATHS.src, NAMES.index)}.html`,
printHtml: `${path.join(PATHS.src, NAMES.print)}.html`,
// Chrome Extension Development
popupHtml: `${path.join(PATHS.src, NAMES.popup)}.html`,
optionsHtml: `${path.join(PATHS.src, NAMES.options)}.html`,
backgroundHtml: `${path.join(PATHS.src, NAMES.background)}.html`
};
// Third-party (vendor) libraries to include
// const VENDORS = ['react', 'bootstrap', 'lodash', 'jQuery']; // Relative paths to node_modules
// Note: These are relative
const ASSETS = {
images: path.join(NAMES.assets, NAMES.images),
fonts: path.join(NAMES.assets, NAMES.fonts)
};
// CleanWebpackPlugin config
const pathsToClean = [PATHS.dist, PATHS.build];
const cleanOptions = {
root: __dirname,
exclude: ['shared.js'],
verbose: true,
dry: false
};
// CopyWebpackPlugin config
const copyPattern = [
// {
// from: NAMES.assets,
// to: NAMES.assets
// },
// {
// from: path.join(NAMES.include, 'contentScript.css')
// },
// {
// from: 'manifest.json',
// transform(content, copyPath) {
// // generates the manifest file using the package.json informations
// return Buffer.from(
// JSON.stringify({
// ...JSON.parse(content.toString())
// // description: env.npm_package_description,
// // version: env.npm_package_version
// })
// );
// }
// }
];
const copyOptions = {
// ignore: ['*.js'],
context: PATHS.src
};
module.exports = (env = {}) => {
// webpack injects env variable, into webpack config.
// perfect to check for production.
// remember to specify --env.production in command
// (if in production mode).
const isProduction = env.production === true;
return {
entry: {
index: FILE_PATHS.indexJs
// Chrome Extension Development
// popup: FILE_PATHS.popupJs,
// contentScript: FILE_PATHS.contentScriptJs
// options: FILE_PATHS.optionsJs,
// background: FILE_PATHS.backgroundJs,
// vendor: VENDORS
},
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'inline-source-map',
optimization: {
splitChunks: {
chunks: 'all'
}
},
output: {
filename: isProduction ? '[name].[chunkhash:8].js' : '[name].js',
// chunkFilename determine name of non-entry chunk files,
// for example dynamic imports in the app
chunkFilename: isProduction ? '[name].[chunkhash:8].js' : '[name].js',
path: PATHS.dist
},
plugins: [
// new webpack.SourceMapDevToolPlugin({
// filename: '[file].map',
// exclude: ['vendor', 'runtime']
// }),
new webpack.DefinePlugin({
// specifies environment variable for dependencies.
// does not apply to browser runtime environment
// (process.env is provisioned by Node)
'process.env.NODE_ENV': isProduction ?
JSON.stringify('production') :
JSON.stringify('development')
}),
// new BundleAnalyzerPlugin(),
new CleanWebpackPlugin(pathsToClean, cleanOptions),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
// does not work with Hot Module Replacement (HMR)
// allows HMR in development (will only use this plugin in production)
filename: isProduction ? '[name].[contenthash].css' : '[name].css',
chunkFilename: isProduction ? '[id].[contenthash].css' : '[id].css'
}),
new webpack.HashedModuleIdsPlugin(),
isProduction ?
new UglifyJSPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}) :
() => {},
new CopyWebpackPlugin(copyPattern, copyOptions),
// new WriteFilePlugin(),
new HtmlWebpackPlugin({
template: FILE_PATHS.indexHtml,
filename: `${NAMES.index}.html`
})
// new HtmlWebpackPlugin({
// template: FILE_PATHS.popupHtml,
// filename: `${NAMES.popup}.html`,
// excludeChunks: [NAMES.contentScript]
// In dev mode, chunks excluded vendor chunk (which holds CSS).
// Above check fixes it.
// }),
// new HtmlWebpackPlugin({
// filename: `${NAMES.contentScript}.html`,
// excludeChunks: [NAMES.popup, 'runtime'] // Runtime only needed in one HTML
// }),
// new HtmlWebpackPlugin({
// template: FILE_PATHS.optionsHtml,
// filename: `${NAMES.options}.html`,
// chunks: isProduction ? [NAMES.options] : ''
// }),
// new HtmlWebpackPlugin({
// template: FILE_PATHS.backgroundHtml,
// filename: `${NAMES.background}.html`,
// chunks: isProduction ? [NAMES.background] : ''
// }),
// no need for CSS minimization here <-- Done by PostCSS (cssnano)
// new InlineManifestWebpackPlugin(),
// new ManifestPlugin({fileName: 'webpack-manifest.json'}),
],
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.s?[ac]ss$/,
exclude: /node_modules/,
use: [
isProduction ?
MiniCssExtractPlugin.loader :
{
// creates style nodes from JS strings
loader: 'style-loader',
options: {
sourceMap: true,
convertToAbsoluteUrls: true
}
},
{
// CSS to CommonJS (resolves CSS imports into exported CSS strings)
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2
}
},
{
loader: 'postcss-loader',
options: {
config: {
ctx: {
cssnext: {},
cssnano: {},
autoprefixer: {}
}
},
sourceMap: true
}
},
{
// compiles Sass to CSS
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[hash:4].[ext]',
outputPath: ASSETS.images
}
}]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[hash:4].[ext]',
outputPath: ASSETS.fonts
}
}]
},
{
test: /\.(csv|tsv)$/,
use: ['csv-loader']
},
{
test: /\.xml$/,
use: ['xml-loader']
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
options: {
interpolate: 'require',
minimize: true
}
}
}
// {
// test: /\.tsx?$/,
// exclude: /(node_modules|bower_components)/,
// use: 'ts-loader'
// }
]
},
devServer: {
// contentBase: path.join(__dirname, 'dist'),
contentBase: PATHS.dist,
compress: false,
port: 8080,
open: false
}
};
};
7条答案
按热度按时间oaxa6hgo1#
我花了大约5天的工作来理解这个webpack是如何工作的。老实说,我可以说,这是我真的不明白为什么它们是“事实上”的工具的时刻之一。我不明白它有多难,只是让配置文件的工作,因为它应该,在大口地花了我1个小时做同样的事情。
我的问题是所有的网址()个规则(包括字体和图像)被css-loader加载为[object Module],它们被file-loader导出,但从未被加载,所以如果我在css-loader中添加?url=false,它就不会复制文件并导出它们。我不得不说这完全是一个PITA,但我让它工作,我希望它能为世界上的其他人工作,这是用Webpack 4制作。
uz75evzq2#
顺便说一句,你可以关闭对
url()
规则的处理。我不知道为什么这是一个默认行为。r1wp621o3#
我自己能解决这个问题。如果它能帮助别人在未来,请找到下面的解决方案。
1.首先,如果您同时使用
postcss-loader
和postcss-import
插件,并且使用css-loader
,请关闭/删除postcss-import
插件。您不需要多个工具来解析@import
规则。如果加载程序的顺序正确,这实际上不是一个问题,但您最好删除它。1.在sass-loader文档中,您可以阅读以下内容:
由于Sass/libsass不提供url重写,因此所有链接的资源都必须相对于输出。
第二个问题很可能会干扰您的工作。人们很自然地会期望相对引用在指定它们的.scss文件中被解析(就像在常规的.css文件中一样)。幸运的是,有两种解决方案可以解决这个问题:
我决定按照第二点,在 Webpack 配置中的
sass-loader
之上添加resolve-url-loader
。它现在可以按预期工作了。我的最终Webpack配置(目前)如下所示:
快速笔记
1.我注意到Chrome的调试器中“无域”下的源代码Map路径是重复的。如果有人知道原因,请分享
1.记住在
package.json
中包含以下副作用,这样在生产模式下发生的树抖动不会删除提取的css“副作用”:[“.css”、“.scss”]、
nhjlsmyf4#
IE与新URL()不兼容
vfwfrxfs5#
如果有人在使用Webpack 5时遇到了这个问题,并试图从css-loader 5升级到css-loader 6,您可能需要检查this issue,其中的海报有一个与OP类似的问题:
在css-loader 5.2.7中,输入手写笔中的图像被嵌入为输出CSS中的数据- URL。而在css-loader 6中,图像被移动到输出目录中。
有关如何升级到css-loader 6的信息,请参见Notes here-要点如下:
启用esModules选项时,不建议使用~...并且可以从代码中删除
和
file-loader和url-loader已过时,请在资产模块上迁移,因为v6 css-loader正在生成新的URL(...)语法,它默认启用内置资产模块,即类型:所有url()的'asset'
因此,我做了以下工作:
1.已删除.scss文件中的所有“~”
也就是说
变成了
1.我还完全删除了“文件加载器”模块。
所有NPM软件包现在都是最新的,CSS中的URL工作正常。
ss2ws0br6#
我的问题是,webpack 5改变了一切与“资产模块”显然和打破文件加载器。
官方文件对此解释得很清楚:https://webpack.js.org/guides/asset-modules/
TL;DR您可以通过将
type: 'javascript/auto'
添加到规则/加载程序来修复它vwkv1x7d7#
在Webpack 5中,应避免使用
raw-loader
和file-loader
,而应使用asset/source
和asset/resource
。您可以在以下位置阅读有关资产的更多信息:https://webpack.js.org/guides/asset-modules/。它描述了对于Webpack4和更早版本,应该如何使用
file-loader
,对于Webpack5和更高版本,应该如何使用资产模块。