How to use tailwindcss in a custom Nuxt3 module? - module

I am building a custom Nuxt3 module and want to use tailwindcss to style
my components.
However, I am having trouble setting up tailwindcss for my module.
I tried to set it up, like I would with a normal css file:
In the 'src/' folder I have the follwing components:
'runtime/css/tailwind.css':
#import "tailwindcss/base";
#import "tailwindcss/components";
#import "tailwindcss/utilities";
'runtime/tailwind.config.js':
import defaultTheme from ("tailwindcss/defaultTheme")
module.exports = {
content: {
files: [
"./components/**/*.{vue,js}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./modules/**/*.{js,ts,vue}"
],
},
theme: {
extend: {
fontFamily: {
sans: ['"Inter var"', ...defaultTheme.fontFamily.sans],
},
},
},
variants: {
extend: {},
}
};
'module.ts':
import { resolve } from 'path'
import { fileURLToPath } from 'url'
import { defineNuxtModule, addPlugin, addComponent } from '#nuxt/kit'
export interface ModuleOptions {
css: boolean
}
export default defineNuxtModule<ModuleOptions>({
meta: {
name: '#nuxt-module/polkadotjs-wallet',
configKey: 'polkadotjs-wallet'
},
defaults: {
css: true,
},
setup (options, nuxt) {
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
nuxt.options.build.transpile.push(runtimeDir)
// add the plugin
addPlugin(resolve(runtimeDir, 'plugin'))
// add components
const componentsDir = resolve(runtimeDir, "components")
addComponent({
name: "Hello",
filePath: resolve(componentsDir, "Hello.vue")
})
if(options.css) {
nuxt.options.css.push(resolve(runtimeDir, "css/tailwind.css"))
}
}
})
While this approach works to use normal css styling, I cannot make tailwind work like that.
Running it like this does not give me an error, but it also does not enable me to use tailwind.

I think I find a way, but I'm just discovering Nuxt 3.
Maybe my answer won't be perfect, but as far as I read the documentation and the #nuxtjs/tailwindcss code, that's all I found to work.
move your runtime/css/tailwind.css to runtime/tailwind.css
I'm not sure this file is really useful, as there is a default one provided by #nuxtjs/tailwindcss (see in your node_modules/#nuxtjs/tailwindcss/dist/runtime/tailwind.css)
update your tailwind.config.js for content property. It's an array of string for me. Actually, your paths are relatives. But in your app, these paths will take the components app and not the one of your module. You need to give absolute paths.
import defaultTheme from ("tailwindcss/defaultTheme")
import { fileURLToPath } from 'node:url'
const srcDir = fileURLToPath(new URL('../', import.meta.url))
/** #type {import('tailwindcss').Config} */
export default {
content: [
srcDir + '/**/*.{js,ts,vue}', // or separate in folders ?
],
theme: {
extend: {
fontFamily: {
sans: ['"Inter var"', ...defaultTheme.fontFamily.sans],
},
},
},
variants: {
extend: {},
}
};
last part, but the most important, you need to update your module.ts. I would write yours like this :
async setup (options, nuxt) {
const runtimeDir = fileURLToPath(new URL('../src/runtime', import.meta.url))
/**
* Here, you use the installModule to specify that
* your module USE the #nuxtjs/tailwindcss module.
* I think this is the way to add the tailwind module
* to your playground, or the app that will use your module
*/
await installModule('#nuxtjs/tailwindcss', {
/**
* Here, you specify where your config is.
* By default, the module have a configPath relative
* to the current path, ie the playground !
* (or the app using your module)
*/
configPath: resolve(runtimeDir, 'tailwind.config'),
})
// add components
const componentsDir = resolve(runtimeDir, "components")
addComponent({
name: "Hello",
filePath: resolve(componentsDir, "Hello.vue")
})
/**
* for these lines, I don't know if they are still useful
* please check them before keeping them :-)
*/
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
nuxt.options.build.transpile.push(runtimeDir)
// add the plugin
addPlugin(resolve(runtimeDir, 'plugin'))
if(options.css) {
nuxt.options.css.push(resolve(runtimeDir, "css/tailwind.css"))
}
}
Does this help you ?
References :
installModule for Nuxt3 Modules
default configPath for #nuxtjs/tailwindcss

Related

Changes in yaml files displays only after restart metro server

I am using babel-plugin-content-transformer library to use yaml files. I need to use them instead of json in react-i18next localisation library. It works fine but there is one issue: when i change some translation in .yml file the changes displays only after I restart metro server. Reload also doesn't works, I see no changes after I pressed 'r' to reload server. To see changes I need to stop and after that run server again.
My babel.config.js is
module.exports = function (api) {
const presets = [['module:metro-react-native-babel-preset']]
const plugins = [
['module-resolver', {
root: ['./'],
extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
alias: {
'#bluecentury': './src',
}
}],
['module:react-native-dotenv', {
'moduleName': '#vemasys/env',
}],
['react-native-reanimated/plugin'],
['content-transformer', {
transformers: [{
file: /\.ya?ml$/,
format: 'yaml'
}]
}]
]
api.cache(false)
return {
presets,
plugins
}
}
my i18n.ts is
import i18n from 'i18next'
import {initReactI18next} from 'react-i18next'
import translationEN from './enyaml.yml'
// import translationEN from './en.json'
const resources = {
en: {
translation: translationEN,
},
}
i18n.use(initReactI18next).init({
resources,
lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
})
When I'm using en.json everything works fine.

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

Imports path issue when using TSDX with preservedModules and postCSS

I'm using TSDX for my ui-kit library along with postCSS for scss-modules. And it works pretty fine. Now i want to use preserveModules for treeshaking to not load all ui-kit components in application, but only imported ones.
So i added some configs to my tsdx.config.js and now it looks like this:
const autoprefixer = require('autoprefixer')
const cssnano = require('cssnano')
const babel = require('rollup-plugin-babel')
module.exports = {
/**
* #param {import("rollup/dist/rollup").InputOptions} config
*/
rollup(config, options) {
if (options.format === 'esm') {
config = { ...config, preserveModules: true }
config.output = {
...config.output,
dir: 'dist/',
entryFileNames: '[name].esm.js',
}
delete config.output.file
}
config.plugins.push(
postcss({
modules: true,
plugins: [
autoprefixer(),
cssnano({
preset: 'default',
}),
],
inject: true,
extract: false,
minimize: true,
})
)
return config
},
}
For some reason builded components in /dist folder have wrong imports (extra '../').
For example in Button.esm.js
import { objectWithoutPropertiesLoose as _objectWithoutPropertiesLoose } from '../../../../_virtual/_rollupPluginBabelHelpers.js'
instead of
import { objectWithoutPropertiesLoose as _objectWithoutPropertiesLoose } from '../../../_virtual/_rollupPluginBabelHelpers.js'
Changing postcss option inject: false fix imports but broke components styles.
I'm not sure is it a tsdx issue or postcss issue.
Asking for any help and advice.

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

Vetur error when using multiple queries in same .gql file

I am using Vue typeScript with GraphQL. Whenever I try to use a query using deconstructor I get an error from Vetur. I am able to use GetPostData query in the Vue Component and its working fine.
Trying to use this - https://github.com/apollographql/graphql-tag#support-for-multiple-operations
Vue File
import { GetPostData } from "../../util/queries/getPageData.gql";
getPageData.gql
query GetPostData {
continents {
code
}
}
query GetCountries($code: String!) {
country(code: $code) {
code
}
}
Vue.config.js
const antdTheme = require("./src/theme.js");
module.exports = {
publicPath: "/",
pwa: {
iconPaths: {
favicon32: "./favicon.png",
favicon16: "./favicon.png",
appleTouchIcon: "./favicon.png",
maskIcon: "./favicon.png",
msTileImage: "./favicon.png"
}
},
css: {
loaderOptions: {
less: {
modifyVars: antdTheme,
javascriptEnabled: true
}
}
},
chainWebpack: config => {
// GraphQL Loader
config.module
.rule("graphql")
.test(/\.(graphql|gql)$/)
.use("graphql-tag/loader")
.loader("graphql-tag/loader")
.end();
}
};
I think it states that's what you can do but I don't think you really can.
It's better to put all your queries in a javascript file and import 'graphql-tag' to store queries instead of using a .gql file.
Just tested and Vetur didn't complain, could have been a bug that is already fixed.
According to graphql-tag package this case is supported (docs), so if Vetur complains must be an issue with the extension itself.