无法从 webpack 资产库模块解析 css url
Can't resolve css url from webpack asset librarymodule
我能够输出一个资产库和许多其他库,这些库作为远程联合模块和深度导入库工作,以防我没有连接到远程或者我没有在消费者端使用 webpack。
现在的问题是我的所有资产都导出一个模块,该模块要么将原始数据作为 uri,要么将字符串指向正确的资产。例如:bird.svg 输出到 dust 及其哈希加上解析为文件 bird-[hash].svg.
的模块
以上内容在 javascript 中非常棒,但在 css 中就没那么好了。现在我无法重写 url() 以指向正确的远程路径,就像 sg:
//since I don't know when the assets will change names I can't refer to it directly. So I would need to first read the string from the bird.js module. Append the publicPath and then rewrite the url.
.someClass {
background-image: url('/assets/bird.js')
}
//the above won't work for obvious reasons.
所以,问题是我该如何解决这个问题?或者有没有装载机?我检查了 resolve url 加载程序,但它似乎不是所需要的。
好的,我通过将附加数据作为变量传递给 sass-loader 解决了这个问题。这样我就可以评估文件的实际名称,并将其作为 sass 映射之前并从 sass.
处理它
//I am using glob to return an object with all the assets.
//This can probably be automated better. That would be an easier way.
//But this way works for me in all 3 scenarios, node, browser and federated module.
//Also has caching ootb for the assets.
const assetsPaths = {
...glob.sync('../assets/dist/img/**.node.js').reduce(function (obj, el) {
obj['img/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {}), ...glob.sync('../assets/dist/fonts/**.node.js').reduce(function (obj, el) {
obj['fonts/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {})
};
//...
{
loader: 'sass-loader',
options: {
additionalData: "$assets: '" + assetsMap + "';",
sourceMap: true,
sassOptions: {
outputStyle: "compressed",
},
}
},
//...
您还需要禁用url重写
{
loader: 'css-loader',
options: {
url: false,
}
},
然后您可以在 sass 文件中使用资产地图:
@font-face {
font-family: 'Some Font';
src: local('Some Font');
src: url("#{map-get($assets, SomeFont)}");
}
您可能需要将您的项目设置排序为单声道存储库,并且您还需要使用两个包构建这些资产库。
一个用于节点,因此您可以在捆绑时使用实际资产的字符串路径 sass/whatever。
另一个用于正常从浏览器加载它。
更新:
我没有做所有这些,而是使用从 'webpack-manifest-plugin' 生成的清单来构建要在 sass.
中使用的 $assets 映射
const assetsManifest = JSON.parse(fs.readFileSync('../assets/dist/manifest.json'));
const assetsMapFn = asset => `'${asset[0]}':'${asset[1]}'`;
const assetsMap = `(
${Object.entries(assetsManifest).map(assetsMapFn).join(',')}
); `;
如果有人知道更好的方法,请回复或评论。
我能够输出一个资产库和许多其他库,这些库作为远程联合模块和深度导入库工作,以防我没有连接到远程或者我没有在消费者端使用 webpack。
现在的问题是我的所有资产都导出一个模块,该模块要么将原始数据作为 uri,要么将字符串指向正确的资产。例如:bird.svg 输出到 dust 及其哈希加上解析为文件 bird-[hash].svg.
的模块以上内容在 javascript 中非常棒,但在 css 中就没那么好了。现在我无法重写 url() 以指向正确的远程路径,就像 sg:
//since I don't know when the assets will change names I can't refer to it directly. So I would need to first read the string from the bird.js module. Append the publicPath and then rewrite the url.
.someClass {
background-image: url('/assets/bird.js')
}
//the above won't work for obvious reasons.
所以,问题是我该如何解决这个问题?或者有没有装载机?我检查了 resolve url 加载程序,但它似乎不是所需要的。
好的,我通过将附加数据作为变量传递给 sass-loader 解决了这个问题。这样我就可以评估文件的实际名称,并将其作为 sass 映射之前并从 sass.
处理它//I am using glob to return an object with all the assets.
//This can probably be automated better. That would be an easier way.
//But this way works for me in all 3 scenarios, node, browser and federated module.
//Also has caching ootb for the assets.
const assetsPaths = {
...glob.sync('../assets/dist/img/**.node.js').reduce(function (obj, el) {
obj['img/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {}), ...glob.sync('../assets/dist/fonts/**.node.js').reduce(function (obj, el) {
obj['fonts/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {})
};
//...
{
loader: 'sass-loader',
options: {
additionalData: "$assets: '" + assetsMap + "';",
sourceMap: true,
sassOptions: {
outputStyle: "compressed",
},
}
},
//...
您还需要禁用url重写
{
loader: 'css-loader',
options: {
url: false,
}
},
然后您可以在 sass 文件中使用资产地图:
@font-face {
font-family: 'Some Font';
src: local('Some Font');
src: url("#{map-get($assets, SomeFont)}");
}
您可能需要将您的项目设置排序为单声道存储库,并且您还需要使用两个包构建这些资产库。
一个用于节点,因此您可以在捆绑时使用实际资产的字符串路径 sass/whatever。 另一个用于正常从浏览器加载它。
更新:
我没有做所有这些,而是使用从 'webpack-manifest-plugin' 生成的清单来构建要在 sass.
中使用的 $assets 映射const assetsManifest = JSON.parse(fs.readFileSync('../assets/dist/manifest.json'));
const assetsMapFn = asset => `'${asset[0]}':'${asset[1]}'`;
const assetsMap = `(
${Object.entries(assetsManifest).map(assetsMapFn).join(',')}
); `;
如果有人知道更好的方法,请回复或评论。