Reference to assets from dist folder with vue + webpack in electron app - vue.js

I am using vuejs + webpack + electron.
I have hard time retrieving the path to my asset.
My project structure is the following:
/my-project
/app
/components
componentA.vue
...
App.vue
main.js
/dist
/assets
/icons
/a.png
package.json
webpack.config.js
I load the static asset in the dist folder with file-loader.
My webpack.config.js looks like:
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './app/main.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
}
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015'],
plugins: ['transform-runtime']
}
}
},
{
test: /\.(jpe?g|png|gif|svg|ico)$/,
exclude: /node_modules/,
loader: "file-loader?name=/assets/icons/[name].[ext]"
},
]
},
resolve: {
alias: {
vue: 'vue/dist/vue.js'
}
},
plugins: [
new webpack.ExternalsPlugin('commonjs', [
'electron'
])
],
node: {
__dirname: true,
fs: 'empty',
module: 'empty',
net: 'empty',
tls: 'empty'
},
externals: ["fs"]
}
In the file componentA.vue I am trying to do the following:
<template>
<div>
<img :src= "link">
</div>
</template>
<script>
import Aa from '../assets/icons/a.png'
export default {
data () {
return {
link: '',
}
},
created() {
this.link = Aa;
},
...
</script>
But I have the following error:
Failed to load resource: net::ERR_FILE_NOT_FOUND file:///a.png
The images appear loaded in the correct path in the dist/assets/icons but electron is trying to load it from
file:///assets/icons/a.png
I'm new to webpack and tried to load it in different ways but i can't make it work, can you help me in resolving this issue ? Thanks a lot !

Related

How can I use my static CSS with VueJS and webpack

I’m struggling a little with webpack, VUE and my CSS static files. See, I’d like to inject the styles that are in the Single File Components with the and I also want to have my static CSS file that has some useful classes. I’m running webpack 4 and I don’t clearly know how to approach the static CSS file situation.
This is my webpack config so far:
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMerge = require('webpack-merge');
const makeConfig = (mode) => require(`./build-utils/webpack.${mode}.js`)(mode)
const MiniCss = require('mini-css-extract-plugin');
module.exports = (env) => {
return WebpackMerge.merge(
{
mode: env.mode,
entry: './src/main.js',
output: {
filename: '[name].js',
publicPath: '/',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.vue$/,
exclude: /node_modules/,
loader: 'vue-loader'
},
{
test: /\.(js)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader' }
]
},
{
test: /\.(css)/,
use: [
MiniCss.loader,
'css-loader'
],
include: /\assets\.css$/
},
{
test: /\.(css)/,
use: [
'style-loader',
'css-loader'
],
exclude: /\assets\.css$/,
},
{
test: /\.(png|jpg|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
esModule: false
}
}
]
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: 'index.html'
}),
new MiniCss()
]
},
makeConfig(env.mode)
)
}
I have my statics css under /src/assets. Then my CSS assets gets imported in the entry point javascript’s file. The problem is that I don’t get my static CSS file emitted. What’s the solution for both: have my static css and the Single Component CSS.
Thank you!

<v-img> doesn`t work with static image. [Vuetify] Image load failed src: #/assets/img/logo.png

I have simple vuetify image tag which has to load image file from project directory, but it never works
<v-img src="#/assets/img/logo.png"></v-img>
Vue cannot load image neither with relative path, nor with absolute. src with # and require() also don`t work. When i try to require() image, compiler fails and says
Module not found: Error: Can't resolve './assets/logo.png' in 'D:\Projects\ExpertRestRELEASE\src\main\resources\static\js\pages'
It seems like a webpack problem, but i don`t have any idea how to solve it
Project structure:
webpack.config.js
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.join(__dirname, 'src', 'main', 'resources', 'static', 'js', 'main.js'),
devServer: {
contentBase: './dist',
disableHostCheck: true,
compress: true,
port: 8000,
allowedHosts: [
'localhost:9000'
],
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
}
]
},
plugins: [
new VueLoaderPlugin()
],
resolve: {
modules: [
path.join(__dirname, 'src', 'main', 'resources', 'static', 'js'),
path.join(__dirname, 'node_modules'),
],
}
}
P.S url links work fine
You're trying to request /assets which doesn't exist in your project, you only have /assets.img in there, so why are you requesting /assets/img/logo.png instead of /assets.img/logo.png? And why did you name this folder like this? You should probably rename it to just assets.
Also, there's another thing, look at the error, it tells you that it cannot find folder /assets inside /src/main/resources/static/js/pages because that /assets you're trying to get is 3 levels up, inside the /resources, not inside /pages
Try this:
<v-img :src="logoPath"></v-img>
...
data() {
return {
logoPath: path.join(__dirname, 'src', 'main', 'resources', 'assets', 'logo.png')
}
}
You can also try these:
<v-img src="./src/main/resources/assets/logo.png"></v-img>
<v-img src="./resources/assets/logo.png"></v-img>
<v-img src="./assets/logo.png"></v-img>
<v-img :src="__dirname + '/src/main/resources/assets/logo.png'"></v-img>
<v-img :src="__dirname + 'src/main/resources/assets/logo.png'"></v-img>
<v-img :src="__static + '/assets/logo.png'"></v-img>
<v-img :src="__static + 'assets/logo.png'"></v-img>

Vue SFC styles not being extracted in webpack production build

Trying to add vue (and SFCs) to my webpack app. The <template> and <script> blocks work fine, but for some reason the styles in the <style> block are not being extracted for production build.
In the dev build, it's extracting the .vue <style> block to a separate css file (named for the entrypoint). Which is OK but I'd prefer they went into my main stylesheet.
But no matter what I try, I can't get any .vue styles to show up (in any file) for the production build.
This is an abbreviated version of my webpack config:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
...
module.exports = (env) => {
return {
entry: {
app: ["./src/polyfills.js", "./src/scss/styles.scss", "./src/app.js"],
...
testview: "./src/js/views/TestView.js"
},
output: {
path: assets,
filename: "[name].[hash].js",
publicPath: "/static/"
},
resolve: {
modules: ["node_modules", "src"],
alias: {
vue$: "vue/dist/vue.esm.js"
},
extensions: ["*", ".js", ".vue"]
},
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader"
},
{
test: /\.js?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: [
[
"#babel/preset-env",
{
targets: {
browsers: ["> 1%", "last 2 versions", "ie >= 11"]
}
}
]
],
plugins: ["#babel/plugin-proposal-class-properties"],
code: true,
comments: true,
cacheDirectory: true,
babelrc: false
}
}
]
},
{
test: /\.s?[ac]ss$/,
use: [
"vue-style-loader",
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: ifNotProduction()
}
},
{
loader: "postcss-loader",
options: {
ident: "postcss",
sourceMap: ifNotProduction(),
plugins: () =>
ifProduction([
require("autoprefixer")({
preset: "default"
}),
require("cssnano"),
require("css-mqpacker")
])
}
},
{
loader: "sass-loader",
options: {
sourceMap: ifNotProduction()
}
}
]
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 2,
minSize: 0
},
styles: {
name: "styles",
test: /\.css$/,
chunks: "all",
enforce: true
}
}
},
occurrenceOrder: true
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: "style.[hash].css"
}),
new HtmlWebpackPlugin({
hash: true,
inject: false,
template: "./src/jinja-templates/base.html.j2",
filename: `${templates}/base.html.j2`,
})
]
};
};
The .vue file I'm using is this demo one. I'm trying to import it into the entrypoint called 'testview' which contains simply:
import Vue from "vue";
import MainContent from "../components/main-content";
let MainComponent = Vue.extend(MainContent);
new MainComponent().$mount("#mainContent");
Did figure it out. I had to remove sideEffects: false from my package.json. This issue explains it further.
Still would like to know how to extract the .vue styles to my main stylesheet As it is now, the .vue styles are extracting to a separate stylesheet (dev and production).

How can I make FontAwesome work with vue-cli webpack-simple template?

I generate a default project with vue-cli:
vue init webpack-simple grid-prototype
I install FontAwesome through npm:
npm install --save fontawesome
After that, I include it into main.js with:
import 'font-awesome/css/font-awesome.css'
I execute the app with:
npm run dev
And I get this error:
Failed to compile.
./node_modules/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0
Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
# ./node_modules/css-loader!./node_modules/font-awesome/css/font-awesome.css 7:684-735
# ./node_modules/font-awesome/css/font-awesome.css
# ./src/main.js
# multi (webpack)-dev-server/client?http://localhost:8082 webpack/hot/dev-server ./src/main.js
Here's my webpack.config.js (it's the default one created by the cli):
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "./dist"),
publicPath: "/dist/",
filename: "build.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"]
},
{
test: /\.vue$/,
loader: "vue-loader",
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: "file-loader",
options: {
name: "[name].[ext]?[hash]"
}
}
]
},
resolve: {
alias: {
vue$: "vue/dist/vue.esm.js"
},
extensions: ["*", ".js", ".vue", ".json"]
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: "#eval-source-map"
};
if (process.env.NODE_ENV === "production") {
module.exports.devtool = "#source-map";
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}
What am I doing wrong?
webpack-simple is suitable for quick prototyping and it doesn't have advanced rules.
Solution #1: Use webpack template instead of webpack-simple to avoid this and other issues in the future.
Solution #2: Use FontAwesome from CDN, for example:
https://www.bootstrapcdn.com/fontawesome/
I mean, just add the CDN css to your index.html
Solution #3: Add one more rule to your webpack config
module: {
rules: [
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
As it is in the webpack template:
https://github.com/vuejs-templates/webpack/blob/develop/template/build/webpack.base.conf.js

Vue of Typescript. Error: Module not found: Error: Can't resolve './components/mycomponent.vue'

I am using vue of typescript as well as typescript in Express. Everything worked until i want to use single file component in vue.js.
Here is my component,
<template>
<div>This is a simple component. {{msg}}</div>
</template>
<script lang='ts'>
export default {
data() {
return {
msg: "you"
}
}
}
</script>
My webpack file,
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPugPlugin = require('html-webpack-pug-plugin');
const Webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: {
bundle: [
'./node_modules/bootstrap/dist/js/bootstrap.js',
'./dist/web/views/common/client/ts/_main.js',
'./web/views/common/client/style/main.scss'
]
},
output: {
path: path.resolve(__dirname, 'public'),
filename: '[name].js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
ts: 'ts-loader'
},
esModule: true
}
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader',
options: {
minimize: false
}
}, {
loader: 'sass-loader'
}]
})
},
{
test: require.resolve('jquery'),
loader: 'expose-loader?$!expose-loader?jQuery'
}
]
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js'
}
},
plugins: [
new ExtractTextPlugin('styles.css'),
new HtmlWebpackPlugin({
template: './web/views/common/_layout.pug',
filename: '../web/views/common/layout.pug',
filetype: 'pug'
}),
new HtmlWebpackPugPlugin(),
new Webpack.ProvidePlugin({
jQuery: 'jquery',
$: 'jquery',
Popper: 'popper.js'
})
]
};
If I don't use single file component, everything works, but when i introduce .vue file, it will show this error,
ERROR in ./dist/web/views/about/client/ts/_aboutController.js
Module not found: Error: Can't resolve './components/mycomponent.vue' in '/Users/george/github/bochure/dist/web/views/about/client/ts'
# ./dist/web/views/about/client/ts/_aboutController.js 4:24-63
# ./dist/web/views/common/client/ts/_main.js
# multi ./node_modules/bootstrap/dist/js/bootstrap.js ./dist/web/views/common/client/ts/_main.js ./web/views/common/client/style/main.scss
Can anyone help me? You can also download my source at github and help me out. Many thanks.
git#github.com:geforcesong/bochure.git
I'd suggest you to check the component path first.
If you are embedding one vue component into another then check if both are on the same directory level.
If they are then you can use './component-name.vue' and you will be good to go.
Try to change
'./components/mycomponent.vue'
'../components/mycomponent.vue'
This might work in some cases.