PUG 需要图像(webpack)
pug + webpack 中的图像处理问题。在 PUG 的早期,我不通过 loader 处理图片。我使用了 WebpackCopyPlugin,并写了绝对路径。
像那样:
- let imgPath = '/assets/img/'
img(src=imgPath + 'icons/logo/boto.agency.b.svg')
当我构建项目时,WebpackCopyPlugin 复制了所有图片,使用正确的路径编译了 pug,一切正常。现在我需要通过 Loader 处理图片。根据文档,我需要这样编写路径:img (src = require ('./img.png')) 但通常它不能正常工作。我发现了几个场景。在 src/assets/img 文件夹中有几张图片。
1.
img(src=require('../../../../assets/img/1-1.png'))
或者
img(src=require(`@img/1-1.png`))
// '@img': path.resolve(__dirname, '../../src/assets/img/')
一切正常,在组装过程中我们有 1 个文件 1-1.png。这里我没有在 require 中使用变量,因此这些选项不适合
2.开始使用变量:
- let fileName = '1-1.png'
img(src=require(`@img/${fileName}`))
或者
img(src=require(`../../../../assets/img/${fileName}`))
或者
img(src=require(`@img/`+fileName))
或使用 mixin
在开发模式下一切都很好。项目构建后,发生以下情况 - 文件加载器从文件夹中复制所有文件,尽管我只指定了 1。它是这样发生的:
file-loader test: /\.(png|jpg|gif|svg)$/,
- 资产
- 图像
- 1-1.png
- 2-2.jpg
- 图标
- 3.svg
- 图片
- 3.png
- 3.jp2
- 3.jxr
- 图像
项目构建后,文件夹 public(dist)/assets/img 中将包含除 3.jp2 3.jxr 之外的所有文件(3.png 和 3.svg 也将被复制,即使它们在文件夹中)。这个选项也不合适。我只想接收我指定的那些文件。
3.开始实验
- let fileName = 'img/1-1.png'
img(src=require(`../../../../assets/${fileName}`))
我在开发中遇到错误并同时构建:
throw new Error('回调已被调用。'); ^ 错误:回调已被调用。
- let fileName = 'img/1-1.png'
// '@': path.resolve(__dirname, '../../src/assets/')
img(src=require(`@/${fileName}`))
也是一个错误
4.
- let fileName = '1-1.png'
- let basePath = '../../../../assets/img/'
- let path = basePath+fileName
img(src=require(path))
或者
- let aliasPath = '@/img/'
- let path = aliasPath+fileName
img(src=require(path))
错误:找不到模块“../../../../assets/img/1-1.png”
- let fileName = 'img/1-1.png'
- let basePath = '../../../../assets/'
- let path = fileName+basePath2
img(src=require(path))
错误:找不到模块“../../../../assets/img/1-1.png”
对于任何文件加载器配置,这完全取决于我是否在 equire 中使用变量
问题是什么?
我的 webpack 配置:
/* Base config:
========================================================================== */
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {VueLoaderPlugin} = require('vue-loader');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// Main const. Feel free to change it
const isDev = process.env.NODE_ENV === 'development';
const isProd = !isDev;
const PATHS = {
src: path.join(__dirname, '../../src'),
dist: path.join(__dirname, (isProd ? '../../public' : '../../dist')),
webpack: path.join(__dirname, '../../webpack'),
assets: 'assets/',
};
const fileName = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`
const plugins = (type) => {
const base = [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: `${PATHS.assets}css/${fileName('css')}`,
}),
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery',
'window.jQuery': 'jquery',
}),
new CopyWebpackPlugin({
patterns: [
//{from: `${PATHS.src}/${PATHS.assets}img`, to: `${PATHS.assets}img`},
{from: `${PATHS.src}/${PATHS.assets}fonts`, to: `${PATHS.assets}fonts`},
{from: `${PATHS.src}/pages/php`, to: ``},
{from: `${PATHS.src}/static`, to: ''},
]
}),
new CleanWebpackPlugin(),
];
switch (type) {
case 'html': {
const PAGES_DIR = `${PATHS.src}/pages`;
const PAGES = fs
.readdirSync(PAGES_DIR)
.filter((fileName) => fileName.endsWith('.html'));
base.push(
...PAGES.map(
(page) =>
new HtmlWebpackPlugin({
template: `${PAGES_DIR}/${page}`,
filename: page,
}),
),);
break;
}
case 'pug': {
const PAGES_DIR = `${PATHS.src}/pages/pug/includes/pages`;
const PAGES = fs
.readdirSync(PAGES_DIR)
.filter((fileName) => fileName.endsWith('.pug'));
base.push(
...PAGES.map(
(page) =>
new HtmlWebpackPlugin({
template: `${PAGES_DIR}/${page}`,
filename: (page === 'index.pug' || page === '404.pug' ?
page.replace(/\.pug/, '.html') :
`${page.split('.')[0]}/index.html`),
}),
),);
break;
}
}
const PAGES_PHP = fs
.readdirSync(PATHS.src)
.filter((fileName) => fileName.endsWith('.php'));
base.push(
...PAGES_PHP.map(
(page) =>
new HtmlWebpackPlugin({
template: `${PATHS.src}/${page}`,
filename: `${page}`,
inject: false,
}),
),)
return base
}
module.exports = {
externals: {
paths: PATHS,
},
entry: {
app: ['@babel/polyfill', PATHS.webpack]
// module: `${PATHS.src}/your-module.js`,
},
output: {
filename: `${PATHS.assets}js/${fileName('js')}`,
path: PATHS.dist,
publicPath: isDev ? '/' : '/',
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendors',
test: /node_modules/,
chunks: 'all',
enforce: true,
},
// css: {
// name: 'css',
// test: /\.css$/,
// chunks: 'all',
// enforce: true,
// },
// scss: {
// name: 'scss',
// test: /\.scss$/,
// chunks: 'all',
// enforce: true,
// },
},
},
},
devtool: isDev ? 'source-map' : 'eval',
module: {
rules: [
// TypeScript
{
test: /\.ts$/,
exclude: /node_modules|vue\/src/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
},
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env'
]
}
},
{
test: /\.pug$/,
oneOf: [
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader'],
},
{
use: ['pug-loader'],
}
],
},
{
// Vue
test: /\.vue$/,
loader: 'vue-loader',
options: {
loader: {
scss: 'vue-style-loader!css-loader!sass-loader',
},
postcss: {
config: {
path: PATHS.webpack,
},
},
},
},
{
// Fonts
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
options: {
name: `[name].[ext]`,
outputPath: '/assets/fonts/'
},
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
esModule: false,
name: '[name].[ext]',
outputPath: `${PATHS.assets}/img`,
//publicPath: `/${PATHS.assets}img`,
},
},
],
},
{
// scss
test: /\.scss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {sourceMap: true},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
config: {path: `${PATHS.webpack}/postcss.config.js`},
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-resources-loader',
options: {
resources: [
'./src/assets/scss/core/base.scss',
],
},
},
],
},
{
// css
test: /\.css$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {sourceMap: true},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
config: {path: `${PATHS.webpack}/postcss.config.js`},
},
},
],
},
// {
// test: /\.(html)$/,
// use: [
// {
// loader: 'html-loader',
// // options: {
// // minimize: {
// // removeComments: true,
// // collapseWhitespace: false,
// // },
// // },
// },
// ],
// },
],
},
resolve: {
alias: {
'~': PATHS.src,
'vue$': 'vue/dist/vue.js',
'@': path.resolve(__dirname, '../../src'),
'@img': path.resolve(__dirname, '../../src/assets/img/'),
},
extensions: ['.tsx', '.ts', '.js'],
},
plugins: plugins('pug'),
};