I have a vue 3 app where I set up webpack 5 eventually. As I see I eliminated all my issues now the only thing remains is that it does not load my svg-s and images when I run the webpack serve script in dev mode. How can I configure webpack so that it would bundle my svg-s from the scr/assets folder?
my webpack config:
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const env = process.env.NODE_ENV || 'development';
const mode = process.env.VUE_APP_MODE || 'not-fullstack';
module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
alias: {
vue: '#vue/runtime-dom',
'#': path.join(__dirname, 'src'),
},
fallback: { crypto: false, stream: false },
},
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader',
},
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[hash].[ext]',
},
type: 'asset/resource',
},
{
test: /\.svg$/i,
use: [
{
loader: 'url-loader',
options: {
encoding: false,
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, './public/index.html'),
}),
new VueLoaderPlugin(),
new CopyPlugin([
{ noErrorOnMissing: true, from: './src/assets', to: 'images' },
]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env),
'process.env.VUE_APP_MODE': JSON.stringify(mode),
}),
],
devServer: {
historyApiFallback: true,
compress: true,
port: 3000,
},
};
And I reference my svg-s in my Vue component like this:
<img src="../../assets/logo.svg" alt="logo" />
As you can see I tried with the copy-webpack-plugin, maybe I just configured it wrong.
Thank you for your help in advance!
The config in webpack5 changed a lot
{
loader: 'url-loader',
options: {
encoding: false,
},
This is not working anymore. The url-loader is even removed from the npm packages.
The current way is found in the documentation
https://webpack.js.org/guides/asset-management/#loading-images
Related
any idea how to fix this, the webpack config in the ckeditor folder is set like this:
const path = require("path");
const webpack = require("webpack");
const { bundler, styles } = require("#ckeditor/ckeditor5-dev-utils");
const CKEditorWebpackPlugin = require("#ckeditor/ckeditor5-dev-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
module.exports = {
devtool: "source-map",
performance: { hints: false },
entry: path.resolve(__dirname, "src", "ckeditor.js"),
output: {
// The name under which the editor will be exported.
library: "CKSource",
path: path.resolve(__dirname, "build"),
filename: "ckeditor.js",
libraryTarget: "umd",
libraryExport: "default",
},
optimization: {
minimizer: [
(compiler)=>{
const TerserPlugin = require('terser-webpack-plugin');
new TerserPlugin({
terserOptions: {
compress: {},
}
}).apply(compiler);
}
],
},
plugins: [
new CKEditorWebpackPlugin({
// UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
// When changing the built-in language, remember to also change it in the editor's configuration (src/ckeditor.js).
language: "en",
additionalLanguages: "all",
}),
new webpack.BannerPlugin({
banner: bundler.getLicenseBanner(),
raw: true,
}),
],
module: {
rules: [
{
test: /\.svg$/,
use: ["raw-loader"],
},
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
injectType: "singletonStyleTag",
attributes: {
"data-cke": true,
},
},
},
{
loader: "css-loader",
},
{
loader: "postcss-loader",
options: {
postcssOptions: styles.getPostCssConfig({
themeImporter: {
themePath: require.resolve("#ckeditor/ckeditor5-theme-lark"),
},
minify: true,
}),
},
},
],
},
],
},
};
I tried to delete package-lock.json and delete node_modules and reinstall everything, but it did not work.
Tried other solutions from other Stack overflow questions that had similar issues, nothing worked
this happens for ckeditor by the way.
I would be grateful for any help or advice. I have compiled the configuration of the webpack, everything works in production mode, but the webpack-dev-server does not see static files and gives the error "Cannot get /". How can I solve this problem? Thank you in advance for the answer. Here is my webpack.config.js
const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
// const autoprefixer = require("autoprefixer");
const isProd = process.env.NODE_ENV === "production";
const isDev = !isProd;
const optimization = () => {
const config = {
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -10,
chunks: "all",
},
},
},
};
if (isProd) {
config.minimizer = [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
];
}
return config;
};
module.exports = {
entry: path.resolve(__dirname, "src", "index.js"),
mode: isProd ? "production" : "development",
output: {
path: path.join(__dirname, "build"),
filename: "[name].[contenthash:8].js",
chunkFilename: "[name].[contenthash:8].js",
publicPath: "./",
},
devtool: isDev ? "source-map" : false,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.(eot|ttf|woff|woff2)(\?\S*)?$/,
loader: "file-loader",
options: {
name: "[name][contenthash:8].[ext]",
},
},
{
test: /\.(png|jpe?g|gif|webm|mp4|svg)$/,
loader: "file-loader",
options: {
name: "[name][contenthash:8].[ext]",
outputPath: "assets/img",
esModule: false,
},
},
{
test: /\.s?css$/,
use: [
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
"css-loader",
],
},
],
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: "[name].[contenthash:8].css",
chunkFilename: "[name].[contenthash:8].css",
}),
new HTMLWebpackPlugin({
template: path.join(__dirname, "src", "public", "index.html"),
filename: "start-page.html",
alwaysWriteToDisk: true,
minify: {
collapseWhitespace: isProd,
},
}),
new CleanWebpackPlugin(),
],
resolve: {
alias: {
vue: "#vue/runtime-dom",
},
extensions: ["*", ".js", ".vue", ".json"],
},
optimization: optimization(),
devServer: {
compress: true,
port: 9000,
hot: true,
client: {
overlay: true,
},
},
};
Here is a project folders
According to the doc, you need to set the publicPath in the devServer.
Look at the documentation
module.exports = {
//...
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
},
};
I have the following folder structure (here is the demo app source code):
MyComp.scss:(app\web\src\components\MyComp\MyComp.scss)
I've below URL:
.content{
background-image: url(/icons/myIcon.png); // should resolve to web\icons\myIcon.png
}
Webpack is throwing error for this:
Error: Can't resolve '/icons/myIcon.png' in
'C:\app\web\src\components\
MyContainer.jsx: (app\web\src\containers\MyContainer\MyContainer.jsx) I am using below absolute imports which are giving errors:
import MyComp from 'components/MyComp'; // This should resolve to app\web\src\components\MyComp\MyComp.jsx
import { authorizingUser } from 'myRedux'; // should resolve to app\unify\myRedux\modules\auth\actions.js
Moreover, node_modules imports are also failing:
ERROR in ./node_modules/node-fetch/index.js 10:11-26 Module not found:
Error: Can't resolve 'http' in 'C:\node_modules\node-fetch'
Here is how my webpack config is:
config.js: (app\web\build\config.js)
const path = require('path');
const root = path.resolve(__dirname, '..', '..', '..'); // Project root.
const webRoot = path.resolve(root, 'app', 'web');
const assetPath = path.resolve(root, 'web', 'dist');
module.exports = { root, webRoot, assetPath };
webpack.frontend.config: (app\web\build\webpack.frontend.config.js)
require('dotenv').config();
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const config = require('./config.js');
const PROD = process.env.NODE_ENV === 'production';
const cssLoader = (enableModules = true) => {
return {
loader: 'css-loader',
options: {
modules: enableModules,
sourceMap: !PROD,
importLoaders: 2,
modules: {
localIdentName: PROD ? '[local]__[hash:base64:5]' : '[local]',
},
},
};
};
const postCssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: !PROD,
postcssOptions: {
public: [
'postcss-preset-env',
{
// Options
browsers: 'last 2 versions',
},
],
},
},
};
const sassLoader = {
loader: 'sass-loader',
options: {
sourceMap: !PROD,
},
};
const localStyleLoaders = [cssLoader(), postCssLoader, sassLoader];
// We want to disable css module.
const globalStyleLoaders = [cssLoader(false), postCssLoader, sassLoader];
const devPlugins = [new webpack.HotModuleReplacementPlugin()]; // <- To generate hot update chunk
const prodPlugins = [];
const devEntries = [
`webpack-dev-server/client?path=https://my-domain.com:443`, // <-- Enables web socket connection (needs url & port)
'webpack/hot/dev-server', // <- To perform HMR in the browser
];
const clientAppEntryFilePath = path.resolve(config.webRoot, 'src/client.jsx');
module.exports = {
entry: {
frontEndMain: [
'babel-polyfill',
...(PROD ? [] : devEntries),
clientAppEntryFilePath,
],
},
output: {
path: config.assetPath,
filename: '[name]-[hash].js', // Hash is used to force cache invalidation.
publicPath: PROD
? '/dist'
: `https://my-domain.com:443/dist/`,
},
module: {
rules: [
//JavaScript & JSX
{
test: /\.(jsx|js)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
// For local styles.
{
test: /\.(scss|css)$/,
use: PROD
? [MiniCssExtractPlugin.loader, ...localStyleLoaders]
: ['style-loader', ...localStyleLoaders],
include: path.resolve(config.webRoot, 'src'),
exclude: path.resolve(config.webRoot, 'src', 'theme'),
},
// Global styles
// Just like the normal style loader stack, but without css modules so we don't modify
// classnames for our style libraries like bootstrap, slick, etc
{
test: /\.(scss|css)$/,
use: PROD
? [MiniCssExtractPlugin.loader, ...globalStyleLoaders]
: ['style-loader', ...globalStyleLoaders],
include: [path.resolve(config.webRoot, 'src', 'theme'), /node_modules/],
},
// Images: Copy image files to build folder
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
loader: 'url-loader',
options: {
limit: 10240,
},
},
{
test: /\.woff2?(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'mimetype=image/svg+xml',
},
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
},
],
},
resolve: {
modules: [
'node_modules',
// Since I am using absolute import for custom modules/js. So this is required.
'app',
'app/unify',
'app/web/src',
],
extensions: ['.js', '.jsx'],
},
plugins: [
...(PROD ? prodPlugins : devPlugins),
new CleanWebpackPlugin(),
// Since I have hashed frontEnd js/css, so this generates assets info file on root and
// which has assets info.
new AssetsPlugin({
path: config.root,
filename: 'web-frontend-assets.json',
prettyPrint: true,
}),
new webpack.DefinePlugin({
// To resolve this error on production build.
// "You are currently using minified code outside of NODE_ENV === 'production'"
'process.env': {
NODE_ENV: JSON.stringify(PROD ? 'production' : 'development'),
PLATFORM: JSON.stringify(process.env.PLATFORM),
WEB_ENV: JSON.stringify(process.env.WEB_ENV),
},
__CLIENT__: true,
__SERVER__: false,
__DEVELOPMENT__: process.env.NODE_ENV !== 'production',
}),
],
devServer: {
https: {
key: fs.readFileSync(`${config.webRoot}/certs/key.pem`),
cert: fs.readFileSync(`${config.webRoot}/certs/cert.pem`),
},
host: 'my-domain.com',
port: '443',
quiet: true,
inline: true,
hot: true,
compress: true, // <- Enables HMR in webpack-dev-server and in libs running in the browser
historyApiFallback: true,
disableHostCheck: true,
clientLogLevel: 'silent',
publicPath: `https://my-domain.com:443/dist/`,
contentBase: `https://my-domain.com:443`,
headers: { 'Access-Control-Allow-Origin': '*' },
stats: { colors: true },
},
node: false,
stats: {
preset: 'detailed',
assets: true,
builtAt: true,
moduleAssets: false,
assetsSpace: 15,
modulesSpace: 15,
colors: true,
env: true,
errors: true,
errorDetails: true,
errorStack: true,
reasons: true,
modules: true,
},
};
package.json:
"scripts": {
"start-frontend": "webpack --config ./app/web/build/webpack.frontend.config.js"
},
I am not sure, what exactly I need to pass in entry.frontEndMain, output.publicPath, devServer.publicPath, devServer.contentBase
How can i ignore the script tag in Html webpack plugin?
Because I have added this
<script src="cordova.js"/>
tag into my index.html template anonymously for my app development.
See my configuration in Webpack.config.js:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: ["html-loader"],
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
I just wanted to ignore the script on production and I have researched this many times but unfortunately I don't see any solution
So, if I got the problem right, you want to ignore a certain resource when bundling for production.
The html-loader has an option to filter sources based on attribute, attribute value, context file and anything you have available in you webpack.config.js.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Assuming you are passing arguments to your webpack config like argv.mode
const PRODUCTION = true;
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
sources: {
urlFilter: (attribute, value, resourcePath) => {
if (PRODUCTION && /cordova.js$/.test(value)) {
return false;
}
return true;
},
}
},
},
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
In the html module rule, I added an options property to html-loader with an example how you could ignore a certain resource with urlFilter. Check the html-loader docs on filtering resources
You will need to get a reference to the variables you passed to your cli like --mode eg. line 5-6. (Not in the current example) See webpack docs on env vars.
I have the following problem when running the webpack dev server:
when I run npm start, it show the following:
➜ directory git:(staging) ✗ npm start
directory #1.0.0 start directory
BUILD_DEV=1 BUILD_STAGING=1 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js
http://localhost:8080/
webpack result is served from /undefined/
content is served from
directory
404s will fallback to /index.html
Hash: 75773622412153d5f921
Version: webpack 1.12.11
Time: 43330ms
I guess the problem might because the following line:
webpack result is served from /undefined/
When I open the browser at http://localhost:8080/, it appear as follow:
Cannot GET /
and there is no thing in the console.
Do you have any ideas for this problem ?
UPDATE: WEBPACK CONFIG FILE
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const nodeModulesDir = path.resolve(__dirname, 'node_modules');
const deps = [
'moment/min/moment.min.js',
'underscore/underscore-min.js',
];
/* Include SASS path here if you want to this in your sass files:
* #import 'bourbon';
*/
const bourbon = require('node-bourbon').includePaths;
const TARGET = process.env.npm_lifecycle_event;
const ROOT_PATH = path.resolve(__dirname);
const SASS_DEPS = [bourbon].toString();
const BUILD_NUMBER = process.env.CI_BUILD_NUMBER;
const common = {
entry: path.resolve(ROOT_PATH, 'app/index.js'),
output: {
filename: BUILD_NUMBER + '-[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: `/${BUILD_NUMBER}/`,
},
module: {
loaders: [
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass?includePaths[]=' + SASS_DEPS],
include: path.resolve(ROOT_PATH, 'app'),
},
{
test: /\.css$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
'sass?includePaths[]=' + SASS_DEPS,
'postcss'
],
include: path.resolve(ROOT_PATH),
exclude: /(pure\/grids|Grids).*\.css$/,
},
{
test: /(pure\/grids|Grids).*\.css$/,
loaders: [
'style',
'css',
'sass?includePaths[]=' + SASS_DEPS,
],
include: path.resolve(ROOT_PATH),
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&minetype=application/font-woff',
},
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
{
test: /\.json$/,
loader: 'json',
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
template: path.resolve(ROOT_PATH, 'app/index.html'),
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
},
}),
new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'false')),
__STAGING__: JSON.stringify(JSON.parse(process.env.BUILD_STAGING || 'false')),
__API_HOST__: JSON.stringify(process.env.BUILD_STAGING ? 'my.api' : 'my.api'),
}),
],
resolve: {
alias: {
'styles': path.resolve(ROOT_PATH, 'app/styles'),
},
extensions: ['', '.js', '.jsx', '.json'],
},
postcss: function() {
return [
require('postcss-import'),
require('autoprefixer'),
require('postcss-cssnext'),
]
}
};
if (TARGET === 'start' || !TARGET) {
module.exports = merge(common, {
output: {
filename: '[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: '/',
},
devtool: 'eval-source-map',
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: [
'react-hot',
'babel-loader'
],
include: path.resolve(ROOT_PATH, 'app'),
},
],
},
devServer: {
colors: true,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
});
} else if (TARGET === 'build' || TARGET === 'builds') {
const config = {
resolve: {
alias: {},
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: path.resolve(ROOT_PATH, 'app'),
},
],
noParse: [],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compressor: {
screw_ie8: true,
warnings: false,
},
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': { 'NODE_ENV': JSON.stringify(process.env.NODE_ENV) },
}),
],
};
deps.forEach((dep) => {
const depPath = path.resolve(nodeModulesDir, dep);
config.resolve.alias[dep.split(path.sep)[0]] = depPath;
config.module.noParse.push(depPath);
});
module.exports = merge(common, config);
}
Same problem occurred to me when i started using babel-loader > 6.
It was fixed by adding contentBase in webpack dev server configuration.
In my case it looked like this
new WebPackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
contentBase: __dirname + '/public'
}).listen(3000, 'localhost')
I would be great to see your webpack config file to pin point the exact problem, but from the error message, there could be multiple problem
Make sure you are on the right port
Make sure your webpack config has
path and public path setup
Make sure you have contentBase setup as
well
Without seeing your webpack file and more concrete detail, it is quite hard to pinpoint the issue. But you can always go to https://webpack.github.io/docs/webpack-dev-server.html for information on how to set it up.