Why is rollup-plugin-sass not seeing imports using ~? - vue.js

I am trying to port the vue-material library to ESM so I can use it in a project. I am trying to use rollup with rollup-plugin-sass. I have the following rollup config...
import VuePlugin from 'rollup-plugin-vue';
import css from 'rollup-plugin-css-only';
import commonjs from 'rollup-plugin-commonjs';
import sass from 'rollup-plugin-sass';
// const external = Object.keys(pkg.dependencies);
const plugins = [
commonjs(),
VuePlugin(),
sass(),
css()
];
const globals = {
vue: 'Vue'
};
module.exports = {
plugins,
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'esm'
}
};
However, when I build I get...
[!] (VuePlugin plugin) Error: Error: Can't find stylesheet to import.
src/components/MdApp/MdApp.vue 131:9 root stylesheet
I check and line 131 is...
#import "~components/MdAnimation/variables.scss";
This file does seem to exist under the src/components folder but it isn't getting recognized. I also tried this...
sass({
includePaths: [ 'src/' ],
importer(path) {
return { file: path[0] !== '~' ? path : path.slice(1) };
}
}),
But I still get the same thing. How do I configure rollup-plugin-sass to use partial imports using ~?

Related

Add script into HTML using vite and vue 3

I have one js file which needs to be put in the public directory and needs to add it in the final production build as a text/javascript.
I have checked the options in vite config but couldn't find anything useful. The files I add contain a global JSON object and can be accessed directly.
To achieve this, I tried this solution.
vite.config.ts
import { fileURLToPath, URL } from "url";
import path from 'path';
// import test from "./src/assets/test.js"
import test from "./public/test.js"
import { defineConfig , loadEnv} from "vite";
import vue from "#vitejs/plugin-vue";
import { loadingScript } from 'vite-plugin-loading-script'
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory.
// Set the third parameter to '' to load all env regardless of the `VITE_` prefix.
const env = loadEnv(mode, process.cwd(), '')
return {
// vite config
define: {
__APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
__TEST__: test,
},
plugins: [vue()],
server: {
hmr: {
overlay: false,
},
},
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
build: {
// rollupOptions: {
// external: ['__APP_ENV__'],
// output: {
// globals: {
// __APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
// }
// }
// }
}
}
});
test.js
export default {
REDIRECT_URL: "https://example.com/",
API_URL: "https://example.com/",
};
with the above changes, I got the console.log('__TEST__', __TEST__) as expected JSON object but it doesn't work with the production build.
maybe you can try including the js file to the html in the public directory

How can I display the current app version from package.json to the user using Vite?

With create-react-app one could use process.env.REACT_APP_VERSION for this.
Is there an equivalent in Vite?
For React & TypeScript users:
Add a define to your vite.config.ts:
import react from '#vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react()],
define: {
APP_VERSION: JSON.stringify(process.env.npm_package_version),
},
});
If you haven't got one already, define a vite-env.d.ts or env.d.ts and add a declare:
declare const APP_VERSION: string;
You'll now be able to use the variable APP_VERSION anywhere in your code & Vite will substitute it at compile time.
Note: You may need to restart your TS server for the declaration to be picked up by intellisense:
VSCode MacOS: ⌘ + ⇧ + P > Restart TS Server
VSCode Windows: ctrl + ⇧ + P > Restart TS Server
EDIT: For TypeScript, see Jamie's answer to set the types.
If you want to use plugin, see Adarsh's answer
But it's very easy to implement it yourself.
You can use define in vite.config.js. Read about it here
vite.config.js
export default {
plugins: [vue()],
define: {
'__APP_VERSION__': JSON.stringify(process.env.npm_package_version),
}
}
component.vue
<template>
<div>{{ version }}</div>
</template>
<script>
export default {
data () {
version: __APP_VERSION__
},
}
</script>
or with <script setup>
<script setup>
const version = __APP_VERSION__
</script>
<template>
<div>{{ version }}</div>
</template>
You should be able to change '__APP_VERSION__' as long as it doesn't conflict with javascript syntax or other variables.
If you don't want to use define, there is a vite plugin for just this.
https://www.npmjs.com/package/vite-plugin-package-version
// vite.config.js
import loadVersion from 'vite-plugin-package-version';
export default {
plugins: [loadVersion()],
};
Will inject import.meta.env.PACKAGE_VERSION with the version specified in your package.json.
Vite 4, React, Typescript setup
This worked for me.
I imported package.json in vite.config.ts and defined a PACKAGE_VERSION environment variable.
import { defineConfig } from 'vite'
import react from '#vitejs/plugin-react'
import packageJson from './package.json';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
define: {
'import.meta.env.PACKAGE_VERSION': JSON.stringify(packageJson.version)
}
})
I added "resolveJsonModule": true to the compiler options of tsconfig.node.json.
I added "./package.json" to the include array of tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["vite.config.ts", "./package.json"]
}
In order to make intellisense work for PACKAGE_VERSION, I added it to vite-env.d.ts
interface ImportMetaEnv {
readonly PACKAGE_VERSION: string;
// more env variables...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
I could use {import.meta.env.PACKAGE_VERSION} anywhere in my react app to show the package version.
This worked for me:
import { version } from '../../package.json'
In case anyone is interested, this automatically increases the version in package.json and makes it available to the application.
import { defineConfig } from 'vite';
const increasePackageVersion = () => {
try {
const fs = require('fs');
const path = require('path');
const packageFilePath = path.join(__dirname, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageFilePath, 'utf8'));
packageJson.version = packageJson.version.replace(/(\d+)$/, (match, p1) => {
return parseInt(p1) + 1;
}
);
fs.writeFileSync(packageFilePath, JSON.stringify(packageJson, null, 2));
console.log('New version is', packageJson.version);
} catch (error) {
console.log('Error in increasePackageVersion', error);
}
};
export default defineConfig({
build: {
lib: {
entry: 'src/main.js',
formats: ['es']
}
},
plugins: [
increasePackageVersion()],
define: {
'__APP_VERSION__': JSON.stringify(process.env.npm_package_version),
}
});
console.log(__APP_VERSION__);
Below Answer includes
Secure Way of Importing Vue version.
Incrementing semantic versions using npm commands
Secure and Semantic Way of Versioning using npm and env

NPM Module's CSS not applied using #vue/web-component-wrapper VueJS Webcomponents

While developing a Vue web component, using #vue/web-component-wrapper, the styles of npm_modules are not applied. The css actually isn't loaded at all.
Here is my main.js:
import Vue from 'vue';
import wrap from '#vue/web-component-wrapper';
import App from './App.vue';
import '#/modules/filters';
import '#fortawesome/fontawesome-free/css/all.css';
import '#fortawesome/fontawesome-free/js/all';
const wrappedElement = wrap(Vue, App);
window.customElements.define('hello-there', wrappedElement);
Before that, I had the problem, that even my normal css wasn't applied. I resolved this, by help of the answer of this question: Styling not applied to vue web component during development
Even those imported styles in main.js:
import '#fortawesome/fontawesome-free/css/all.css';
won't load at all.
First thought -> there is something wrong with the webpack css-loader/vue-style-loader
Here is my vue.config.js (using the workaround from the above mentioned question):
function enableShadowCss(config) {
const configs = [
config.module.rule('vue').use('vue-loader'),
config.module.rule('css').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('css').oneOf('vue').use('vue-style-loader'),
config.module.rule('css').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('css').oneOf('normal').use('vue-style-loader'),
config.module.rule('postcss').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('postcss').oneOf('vue').use('vue-style-loader'),
config.module.rule('postcss').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('postcss').oneOf('normal').use('vue-style-loader'),
config.module.rule('scss').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('scss').oneOf('vue').use('vue-style-loader'),
config.module.rule('scss').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('scss').oneOf('normal').use('vue-style-loader'),
config.module.rule('sass').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('sass').oneOf('vue').use('vue-style-loader'),
config.module.rule('sass').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('sass').oneOf('normal').use('vue-style-loader'),
config.module.rule('less').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('less').oneOf('vue').use('vue-style-loader'),
config.module.rule('less').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('less').oneOf('normal').use('vue-style-loader'),
config.module.rule('stylus').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('stylus').oneOf('vue').use('vue-style-loader'),
config.module.rule('stylus').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('stylus').oneOf('normal').use('vue-style-loader'),
];
configs.forEach((c) =>
c.tap((options) => {
options.shadowMode = true;
return options;
})
);
}
module.exports = {
chainWebpack: (config) => {
enableShadowCss(config);
},
configureWebpack: {
output: {
libraryExport: 'default',
},
resolve: {
symlinks: false,
},
module: {
rules: [
{
test: /\.ya?ml$/,
use: 'raw-loader',
sideEffects: true,
},
],
},
},
css: {
extract: false,
loaderOptions: {
sass: {
additionalData: `#import "#/styles/_variables.scss";`,
},
},
},
};
So I tried to add css-loader/vue-style-loader manually to webpack with:
chainWebpack: (config) => {
enableShadowCss(config);
config.module
.rule('css')
.test(/\.css$/)
.use('css-loader')
.loader('css-loader')
.end();
},
maybe those styles load now, but it throws an syntax error whilst building anyways:
./node_modules/#fortawesome/fontawesome-free/css/all.css
Syntax Error: CssSyntaxError
(1:4) /Users/.../node_modules/#fortawesome/fontawesome-free/css/all.css Unknown word
> 1 | // style-loader: Adds some css to the DOM by adding a <style> tag
| ^
2 |
3 | // load the styles
I know I know, seems obvious but those lines don't appear in the file at all. Maybe in an imported file though.
Without using the wc-wrapper everything works fine!!
Well anyways... no clue what I should try next. I am a newbie to webpack and Vue!
If anybody has an idea I would greatly appreciate it!
Cheers

ISO proper way to chain Webpack via vue.config.js to add global .scss imports to my .vue files (vue-cli-plugin-nativescript-vue)

I have Vue.js project I've setup previously that dynamically adds defined .scss files to my .vue template files, so I can access my variables, mixins, etc. in the templates without #importing them, or having them duplicate code from imports.
My problem is I'm setting up a NativeScript/Vue.js project with vue-cli-plugin-nativescript-vue and was curious if anyone has successfully setup their webpack to allow the same functionality. It's my understanding that the plugin replaces webpack with the latest when you run, as specified in the docs https://cli.vuejs.org/guide/webpack.html#replacing-loaders-of-a-rule.
Below is my vue.config.js (which compiles with no error) but doesn't seem to be working. I'm probably missing something or don't understand exactly how this is working, any help is appreciated.
const path = require('path')
module.exports = {
chainWebpack: config => {
const ofs = ['vue-modules', 'vue', 'normal-modules', 'normal']
const cssRules = config.module.rule('css')
const postRules = config.module.rule('postcss')
const addSassResourcesLoader = (rules, type) => {
rules
.oneOf(type)
.use('sass-resoureces-loader')
.loader('sass-resources-loader')
.options({
resources: './src/styles/_global.scss', // your resource file or patterns
})
}
ofs.forEach(type => {
addSassResourcesLoader(cssRules, type)
addSassResourcesLoader(postRules, type)
})
return config
},
}
Vue CLI provides a config to augment your CSS loaders:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
scss: {
// sass-loader#^8.0.0
prependData: `import "~#/styles/_global.scss";`,
// sass-loader#^9.0.0 or newer
additionalData: `import "~#/styles/_global.scss";`,
}
}
}
}

Vue Relative Paths with the CLI Service

Running into a problem which is surely related to Webpack.
Tried to do the most basic of services as a smoke test (start small) in a Vue app created by the CLI.
Versions:
Vue CLI: 3.11.0
vue 2.6.10
#vue/CLI-Service 4.0.5
I created a folder called shared inside the src folder of my project. The HelloWorld.vue file is in the components folder. In that file, I imported a data service which I placed inside shared and attempted to use it in the Created event of the HelloWorld component:
<script>
import { dataService } from "../shared";
export default {
name: "HelloWorld",
props: {
msg: String
},
created() {
dataService.addWebSite();
}
};
</script>
The data service is very simple and just meant to hit an API (data.service.js):
import * as axios from 'axios';
const addWebSite = function () {
axios({
method: 'POST',
url: 'https://localhost:44362/WebSites/CreateWebSite',
data: {
name: "Pluralsight",
url: "http://Pluralsight.com"
}
}).then((response) => {
var discard = response.data;
return discard;
});
};
export const dataService = {
addWebSite: addWebSite
};
When I execute npm run serve, I see the following error message:
ERROR Failed to compile with 1 errors 6:13:39 PM
This relative module was not found:
../shared in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/HelloWorld.vue?vue&type=script&lang=js&
I'm guessing this is some kind of Webpack relative path thing, but am at a loss and have not been able to solve it using Google.
The vue.config.js looks like this:
module.exports = {
configureWebpack: {
devtool: 'source-map',
}
};
And I have tried adding a publicPath property of both './' and '/' to that exported object.
Anyone know what's going on?
When you try to import from a folder instead of file, like this
import { dataService } from "../shared";
it implies that you actually want to import from "../shared/index.(any_supported_extension)". But since your file is actually named data.service.js you will have to change your import to
import { dataService } from "../shared/data.service.js";