Nuxt 3 / Vuetify 3 - How to import Material Icons? - vuejs3

I am trying to setup Material Design Icons, and I have the following config:
nuxt.config.ts
import { defineNuxtConfig } from 'nuxt';
export default defineNuxtConfig({
modules: ['#nuxtjs/tailwindcss'],
css: ['vuetify/lib/styles/main.sass', '#mdi/font/css/materialdesignicons.min.css'],
build: {
transpile: ['vuetify'],
},
vite: {
define: {
'process.env.DEBUG': false,
},
},
})`
```
But in terminal I am keep getting the same message whatever I try
[Vue Router warn]: No match found for location with path "/materialdesignicons.min.css.map"
I installed #mdi/font package and followed the vuetify3 official docs but no success.
Also, I have installed Nuxt 3 and Vuetify 3, and dev dependencies sass-loader and sass.
Icons are shown, no problems with display in <v-icon> tag but in terminal I keep getting the same error message.
I have been Googling a lot but I can't seem to find the answer.
Any ideas? Thanks

You need to tell vuetify to use the material icons as icon pack in your plugins/vuetify.ts.
To do so you have to install the mdi font, as you already did, and then set it in the vuetify icons Object in your defineNuxtPlugin.
When done, it should look like this:
import { createVuetify } from 'vuetify'
import {aliases, mdi} from "vuetify/lib/iconsets/mdi";
// make sure to also import the coresponding css
import '#mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader
// Ensure your project is capable of handling css files
export default defineNuxtPlugin(nuxtApp => {
const vuetify = createVuetify({ // Replaces new Vuetify(...)
theme: {
defaultTheme: 'dark'
},
icons: {
defaultSet: 'mdi',
aliases,
sets: {
mdi
}
},
})
nuxtApp.vueApp.use(vuetify)
})
You can then simply use it like this:
<v-icon icon="mdi-minus" />
For a more detailed explanation, visit This Article

I just import materialdesignicons to plugins/vuetify.ts. It works for me.
first install "#mdi/font" and then use this config:
// plugins/vuetify.ts
import { createVuetify } from "vuetify";
import "#mdi/font/css/materialdesignicons.css";
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
ssr: true,
theme: {
defaultTheme: "light",
},
});
nuxtApp.vueApp.use(vuetify);
});

Related

NextJS images are not shown using "export" script

I have a simple NextJs app.
When I'm running the app on a localhost everything seems to work fine - All the images are shown as expected
When I use this script: next build && next export
and browse to my local build, I don't see the images, but instead its "alt" text
The way I import an image:
import React from 'react';
import Image from 'next/image';
import someImage from '../../../public/images/some-image.png';
const Main = () => {
return (
<div>
<Image
src={someImage}
alt="Some Image"
placeholder="blur"
/>
</div>
}
next.config.js
/** #type {import('next').NextConfig} */
const configuration = {
reactStrictMode: true,
eslint: {
dirs: ['./src'],
ignoreDuringBuilds: true,
},
images: {
loader: 'akamai',
path: '',
},
};
module.exports = configuration;
My code design:
Environment:
"next": "13.1.6",
"react": "18.2.0",
Moreover, I tried to use a normal img tag and it causes the same problem.
If anyone here faces the same issue ill appreciate any help!
Refer to this page:
https://nextjs.org/docs/messages/export-image-api
You are attempting to run next export while importing the next/image component using the default loader configuration.
However, the default loader relies on the Image Optimization API which is not available for exported applications.
So, when running static NextJS app with export you cannot use NextJS optimization, as it should run in your non-existent server. You should use cloud solution (https://nextjs.org/docs/api-reference/next/image#loader-configuration) or remove optimization:
module.exports = {
images: {
unoptimized: true,
},
}
(https://nextjs.org/docs/api-reference/next/image#unoptimized)
When importing something statically from the public folder it already knows youre inside it. You only need the following import:
import someImage from 'images/some-image.png';

Configuring Vanilla TS Vite project to keep CSS files separated

I am trying to set up a basic (css) library with vanilla TS and Vite 4.
I want to have a main js and css file at the top level so you can import the whole thing in one go. I also want to have component level imports where you can chose to just import the components js + css. The combined css and JS files are working fine; and the individual component JS file is working fine too.
Currently I'm running into the problem where I can't seem to keep an isolated version of the CSS files next to the JS files after bundling. My build is currently creating :
I've gone over the docs of both Vite and Rollup but I can't seem to figure out how to do the same to my CSS as I'm doing to my JS.
dist
--components
----button
------button.js
--main.css
--main.js
My preferred output would be:
dist
--components
----button
------button.js
------button.css
--main.css
--main.js
In my `main.ts` I'm importing:
import './style.scss'
import './tokens.scss'
import './components/button/button.scss'
vite.config.js
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
cssCodeSplit: false,
manifest: true,
rollupOptions: {
output: {
assetFileNames: () => 'main[extname]',
}
},
lib: {
formats: ['es'],
entry: {
main: resolve(__dirname, 'src/main.ts'),
button: resolve(__dirname, 'src/components/button/button.ts')
},
name: 'CSSFramework',
fileName: (_, fileName) => fileName === 'main' ? '[name].js' : 'components/[name]/[name].js',
},
},
});
Thanks in advance !

nuxt3 and vuetify3 Slow page response

I have created a front development environment using docker compose.
The configuration is nginx + nuxt3 + vuetify3.
I created vue in the Pages directory.
It took 120000ms to display it.
It's so slow that I can't even develop.
I'm trying to see why it's taking so long.
and it looks like it is getting all the vuetify code.
Also some of the requests are giving errors.
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VChip/VChip.css
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VGrid/VGrid.css
http://host.docker.internal/_nuxt/node_modules/nuxt/dist/pages/runtime/app.vue
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VNoSsr/VNoSsr.mjs?v=afbc0ebb
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VColorPicker/util/index.mjs?v=afbc0ebb
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VList/VListChildren.mjs?v=afbc0ebb
http://host.docker.internal/_nuxt/node_modules/vuetify/lib/components/VProgressCircular/VProgressCircular.css?v=afbc0ebb
The access is from host.docker.internal:80 leading to host machine:80 -> nginx container:80 -> nuxt container:3000.
The nuxt server is run by this command.
npx nuxi dev
I don't know why the above massive requests are taking place.
It also does not appear to be normal. What is wrong?
I am new to both nuxt and vuetify.
I am also not familiar with how webpack works.
Having the same issue, maybe it would be wise to add your nuxt config.
Maybe someone can figure out what to do..
Mine is as followed:
{
...
css: ['vuetify/styles'],
build: {
transpile: ['vuetify'],
},
modules: [
// eslint-disable-next-line require-await
async (_options, nuxt) => {
// #ts-ignore
nuxt.hooks.hook('vite:extendConfig', (config) => config?.plugins && config.plugins.push(vuetify({ autoImport: true })))
},
],
...
And plugins/vuetify.ts
// #ts-ignore
import {defineNuxtPlugin, useRuntimeConfig} from '#app'
import {createVuetify} from 'vuetify'
import * as components from 'vuetify/components'
import {aliases, mdi} from 'vuetify/iconsets/mdi-svg'
import { md3 } from 'vuetify/blueprints'
import {useDark} from '#vueuse/core'
export default defineNuxtPlugin((nuxtApp) => {
const isDark = useDark().value
const vuetify = createVuetify({
ssr: true,
// https://next.vuetifyjs.com/en/features/blueprints/
blueprint: md3,
components,
icons: {
defaultSet: 'mdi',
aliases,
sets: {
mdi,
},
},
// https://next.vuetifyjs.com/en/features/theme/
theme: {
defaultTheme: isDark ? 'dark' : 'light',
themes: {
dark, // theme defined earlier
light, // theme defined earlier
},
},
})
nuxtApp.vueApp.use(vuetify)
})

Next.js Global CSS cannot be imported from files other than your Custom <App>

My React App was working fine, using global CSS also.
I ran npm i next-images, added an image, edited the next.config.js, ran npm run dev, and now I'm getting this message
Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.js.
Read more: https://err.sh/next.js/css-global
I've checked the docs, but I find the instructions a little confusing as I am new to React.
Also, why would this error happen now? Do you think it has anything to do with the npm install?
I've tried to remove new files I've added along with their code, but this doesn't fix the problem. I've also tried what the Read more: suggests.
My highest tier component.
import Navbar from './Navbar';
import Head from 'next/head';
import '../global-styles/main.scss';
const Layout = (props) => (
<div>
<Head>
<title>Bitcoin Watcher</title>
</Head>
<Navbar />
<div className="marginsContainer">
{props.children}
</div>
</div>
);
export default Layout;
My next.config.js
// next.config.js
const withSass = require('#zeit/next-sass')
module.exports = withSass({
cssModules: true
})
My main.scss file
#import './fonts.scss';
#import './variables.scss';
#import './global.scss';
my global.scss
body {
margin: 0;
}
:global {
.marginsContainer {
width: 90%;
margin: auto;
}
}
The thing I find the weirdest is that this error came without changing anything to do with CSS, or Layout.js, and it was previously working?
I've moved my main.scss import to the pages/_app.js page, but the styles still aren't coming through. This is what the _app.js page looks like
import '../global-styles/main.scss'
export default function MyApp({ Component, props }) {
return <Component {...props} />
}
Use the built-in Next.js CSS loader (see here)
instead of legacy #zeit/next-sass.
Replace #zeit/next-sass package with sass.
Remove next.config.js. Or do not change CSS loading in it.
Move the global CSS as suggested in the error message.
Since Next.js 9.2 global CSS must be imported in Custom <App> component.
// pages/_app.js
import '../global-styles/main.scss'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
To add styles only to a specific component or page you can use built-in support of CSS modules. (see here)
For example, if you have a component Button.js you can create a Sass file button.module.scss and include it in the component.
Next.js stops complaining when your file has module in naming, e.g., changing import '../global-styles/main.scss'; to import '../global-styles/main.module.scss'; would fix the warning and you could have your styles in the global-styles, or for example, in your component.
No extra dependencies/configurations in next.config.js is required.
You can replace the opinionated (and overly-complex?) NextJs CSS loaders with your own. Here's a simple one for global css:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
reactStrictMode: true,
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Find and remove NextJS css rules.
const cssRulesIdx = config.module.rules.findIndex(r => r.oneOf)
if (cssRulesIdx === -1) {
throw new Error('Could not find NextJS CSS rule to overwrite.')
}
config.module.rules.splice(cssRulesIdx, 1)
// Add a simpler rule for global css anywhere.
config.plugins.push(
new MiniCssExtractPlugin({
experimentalUseImportModule: true,
filename: 'static/css/[contenthash].css',
chunkFilename: 'static/css/[contenthash].css',
})
)
config.module.rules.push({
test: /\.css$/i,
use: !isServer ? ['style-loader', 'css-loader'] : [MiniCssExtractPlugin.loader, 'css-loader'],
})
return config
},
}
Add this to your _app.js
import '../styles/globals.css'
For me the problem was because I had used two module.exports in my next.config.js file like this
const withPlugins = require('next-compose-plugins')
const sass = require('#zeit/next-sass')
const css = require('#zeit/next-css')
const nextConfig = {
webpack: function(config){
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[ext]'
}}
})
return config
}
}
module.exports = withPlugins([
[css],
[sass, {
cssModules: true
}]
], nextConfig)
module.exports = {
env: {
MONGO_URI = 'your uri'
}
}
. 1I modified it to change the export module like this.
const nextConfig = {
webpack: function(config){
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[ext]'
}}
})
return config
},
env: {
MONGO_URI: "your uri"
}
}
2then I deleted the second module.exports
This node package provides a perfect solution for it. You can find it here
Steps to fix it:
1. Add package:
npm install next-remove-imports
or
yarn add next-remove-imports
2. Add this wrapper variable inside your next.config.js
const removeImports = require('next-remove-imports')({
test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/,
matchImports: "\\.(less|css|scss|sass|styl)$"
});
All it is doing is re-enabling global styling import rule for tsx|ts|js|mjs|jsx files
3. Wrap your next config export with this next-remove-imports wrapper. Something like this:
module.exports = removeImports((nextConfig)
4. Now restart your react app and you will be able to import CSS files inside any ts|js|js|jsx|mjs file or component.
Try to include ".module" in your scss file name.
Change main.scss to main.module.scss
Example:
import styles from './todolist-profile-info.module.scss'
You did not need to do anything inside of next.config.js.
Let's assume you are using a global css like Bootstrap, meaning it contains css that is meant to be applied to your entire application and all the different pages inside of it.
Global css files have to be wired up to NextJS in a very particular fashion.
So inside of the pages/ directory you need to create _app.js.
It's critical that the file be named _app.js.
Then at the top of that file you would import Bootstrap css in the following manner:
import 'bootstrap/dist/css/bootstrap.css';
Then you would add the following:
export default ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
So what is going on in that code?
Well, behind the scenes, whenever you try to navigate to some distinct page with NextJS, NextJS will import your component from one of the different files inside your pages/ directory.
NextJS does not just take your component and show it on the screen.
Instead it wraps it up inside of its own custom default component and that is referred to inside of NextJS as the App.
What you are doing by defining the _app.js is to define your own custom app component.
So whenever you try to visit a route inside a browser or your root route, NextJS is going to import that given component and pass it into the AppComponent as the Component prop.
So Component there is equal to whatever components you have in the pages/ directory. And then pageProps is going to be the set of components that you are intending to pass to your files inside of pages/.
So long story short, this thing is like thin wrapper around the component that you are trying to show on the screen.
Why do you have to define this at all?
Well, if you ever want to include some global css to the project, Bootstrap being a global css for example, you can only import global css into the _app.js file.
It turns out that if you try to visit other components or other pages, NextJS does not load up or even parse those files.
So any css you may have imported inside there will not be included in the final HTML file.
So you have a global css that must be included on every single page, it has to be imported into the app file because it's the only file that is guaranteed to be loaded up every single time a user goes to your application.
Don't forget that in addition to importing the css inside of _app.js, you also have to run an npm install bootstrap in your terminal.
You can read more on this here:
https://nextjs.org/docs/messages/css-global
For me, i got this error because I had used improper naming for my project's parent folder, had used special characters in it,
like project#1,
after removing special chars, and changing the folder name to like project-1, the error got away.
In my case there was typo in navbar.module.css
I've written navbar.moduile.css
you must for every component css/scss write navbar.module.css/scss/sass.Next js doesnt compile navbar.css/scss/sass. If hope my answer helps you !.

conditional css in create-react-app

I have default css file and separate css file that should be applied (to owerride default) only when certain conditions are met.
I am using create-react-app wit default import 'file.css' syntax.
What is the best way forward to decide whether to load or not load particular css file dynamically?
The require method only worked in development (as all the CSS is bundled upon build), and the import method did not work at all (using CRA version 3.3).
In our case, we have multiple themes, which cannot be bundled - so we solved this using React.lazy and React.Suspense.
We have the ThemeSelector, which loads the correct css conditionally.
import React from 'react';
/**
* The theme components only imports it's theme CSS-file. These components are lazy
* loaded, to enable "code splitting" (in order to avoid the themes being bundled together)
*/
const Theme1 = React.lazy(() => import('./Theme1'));
const Theme2 = React.lazy(() => import('./Theme2'));
const ThemeSelector: React.FC = ({ children }) => (
<>
{/* Conditionally render theme, based on the current client context */}
<React.Suspense fallback={() => null}>
{shouldRenderTheme1 && <Theme1 />}
{shouldRenderTheme2 && <Theme2 />}
</React.Suspense>
{/* Render children immediately! */}
{children}
</>
);
export default ThemeSelector;
The Theme component's only job, is to import the correct css file:
import * as React from 'react';
// 👇 Only important line - as this component should be lazy-loaded,
// to enable code - splitting for this CSS.
import 'theme1.css';
const Theme1: React.FC = () => <></>;
export default Theme1;
The ThemeSelector should wrap the App component, in the src/index.tsx:
import React from 'react';
import ReactDOM from 'react-dom';
import ThemeSelector from 'themes/ThemeSelector';
ReactDOM.render(
<ThemeSelector>
<App />
</ThemeSelector>,
document.getElementById('root')
);
As I understand, this forces each Theme to be split into separate bundles (effectively also splitting CSS).
As mentioned in the comments, this solution does not present an easy way of switching themes runtime. This solution focuses on splitting themes into separate bundles.
If you already got themes split into separate CSS files, and you want to swap themes runtime, you might want to look at a solution using ReactHelmet (illustrated by #Alexander Ladonin's answer below)
You can use require('file.css') syntax instead. This will allow you to put it inside of a conditional.
e.g.
if(someCondition) {
require('file.css');
}
Use React Helmet. It adds links, meta tags etc into document header dynamically.
Add it into any render method.
import {Component} from 'react';
import ReactHelmet from 'react-helmet';
class Example extends Component{
render(
<ReactHelmet link={
[{"rel": "stylesheet", type:"text/css", "href": "/style.css"}]
}/>);
}
}
You can rewrite it on next <ReactHelmet/> rendering.
One simple solution that I found that works in production is to use vercel's styled-jsx. First, install styled-jsx:
npm install --save styled-jsx
Or if you use Yarn:
yarn add styled-jsx
Now create strings from your css file, so for instance:
const style1 = `
div {
display: flex;
flex-direction: column;
align-items: center;
}
`
const style2 = `
div {
display: flex;
flex-direction: column;
align-items: center;
}
`
And then in your React Component, you can do something like this:
const MyComponent = () => {
return (
<div className='my-component'>
<style jsx>
{
conditionA ? style1: style2
}
</style>
</div>
)
}
Simply add <style jsx>{your_css_string}</style> to the component which you wish to add styling to and you can then to implement conditions just use different strings to import different css styling.
If you are here you most likely are trying to condition a CSS or SCSS import, probably to make some light/dark mode theme or something. The accepted answer works just on mount, after the second css is loaded they are both loaded and you dont have a way to unload them, or actually you have, keep reading...
The use of React lazy and suspense is awesome but in this case we need to help our selves from webpack, because is actually the guy that bundles stuff and can also unbundle stuff, which is what you need, a toggle of css imports basically
Adding webpack lazyStyleTag
Go to your webpack config file and add the following rules
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
// Probly you already have this rule, add this line
exclude: /\.lazy\.css$/i,
use: ["style-loader", "css-loader"],
},
// And add this rule
{
test: /\.lazy\.css$/i,
use: [
{ loader: "style-loader", options: { injectType: "lazyStyleTag" } },
"css-loader",
],
},
],
},
};
Now take your CSS files and change their name to the lazy named convention
You probably have this
styles.css
// or
styles.min.css
Now will be this:
styles.lazy.css
Then create your React theme Provider in a simple React context, this context will wrap your App so it will load the conditioned CSS everytime the context state changes. This context state is going to be availabe anywhere inside your app as well as the setter via a custom hook we will export from the same file, check this out:
import React, {
useEffect, createContext, useState, useContext,
} from 'react';
import { Nullable } from 'types';
// Import both files here like this:
// Import of CSS file number 1
import LightMode from './theme/styles.lazy.css';
// Import of CSS file number 2
import DarkMode from './theme/styles.lazy.css';
interface IContext {
theme: Nullable<string>
toggleTheme: () => void
}
const Context = createContext<IContext>({
theme: null,
toggleTheme: () => { },
});
// Your Provider component that returns the Context.Provider
// Let's also play with the sessionStorage, so this state doesn't
// brake with browser refresh or logouts
const ThemeProvider: React.FC = ({ children }) => {
// Im initialazing here the state with any existing value in the
//sessionStorage, or not...
const [theme, setTheme] = useState<Nullable<string>>(sessionStorage.getItem('themeMode') || 'dark');
// this setter Fn we can pass down to anywhere
const toggleTheme = () => {
const newThemeValue = theme === 'dark' ? 'light' : 'dark';
setTheme(newThemeValue);
sessionStorage.setItem('themeMode', newThemeValue);
};
// Now the magic, this lazy css files you can use or unuse
// This is exactly what you need, import the CSS but also unimport
// the one you had imported before. An actual toggle of import in a
// dynamic way.. brought to you by webpack
useEffect(() => {
if (theme === 'light') {
DarkMode.unuse();
LightMode.use();
} else if (theme == 'dark') {
LightMode.unuse();
DarkMode.use();
}
}, [theme]);
return (
<Context.Provider value={{ theme, toggleTheme }}>
{children}
</Context.Provider>
);
};
export default ThemeProvider;
// This useTheme hook will give you the context anywhere to set the state of // theme and this will toggle the styles imported
export const useTheme = () => useContext(Context);
Remember to put this state on the sessionStorage like in this example so your user has the state available every time it comes back or refreshes the page
Don't forget to wrap the friking App with the Provider:
import ThemeProvider from './ThemeProvider'
const App = () => {
return (
<ThemeProvider>
<App />
</ThemeProvider>
)
}
Now just toggle the CSS imports of your application using your cool useTheme hook
import { useTheme } from './yourContextFile';
// inside your component
const AnyComponentDownTheTree = () => {
const { theme, toggleTheme } = useTheme()
// use the toggleTheme function to toggle and the theme actual value
// for your components, you might need disable something or set active a
// switch, etc, etc
}
Other solution does not work for me. After one day of the search, I obtain bellow solution. In my issue, I have two CSS files for RTL or LTR like app.rtl.css or app.ltr.css
Create a functional component Style like this:
import React, { useState } from "react";
export default function Style(props) {
const [stylePath, setStylePath] = useState(props.path);
return (
<div>
<link rel="stylesheet" type="text/css" href={stylePath} />
</div>
);
}
And then you can call it, for example in App.js:
function App() {
...
return (
<Style path={`/css/app.${direction}.css`} />
)}
direction param contains rtl or ltr and determine which file should be loaded.
I tested some alternatives available in some tutorials and the best for me was to use only classes in css.
One of the problems I encountered when using
require: did not override on some occasions
import: delay generated to load css
The best way for me was to actually put a class switch
.default-sidebar {
--side-text-icon:rgba(255,255,255,.9) !important;
--side-text-section: rgb(255,255,255,.8) !important;
--side-separator-section:#ff944d !important;
}
.dark-sidebar {
--side-text-icon:rgba(255,255,255,.9) !important;
--side-text-section: rgb(255,255,255,.8) !important;
--side-separator-section:#262626 !important;
}
'
<div className={`root-sidebar ${condition?'default-sidebar':'dark-sidebar'}`}></div>

Resources