Disable asset handling in Vite - bundler

I have a PHP project (WordPress theme) with Vite and PostCSS to bundle my JS and CSS files.
The output directory is build and everything worked, but as soon as I import fonts or images in my CSS, Vite copies them into the build folder and changes the paths in the source.
File structure:
styles
|- tailwind.css
|- fonts
|- fa-brands-400.eot
|- fa-brands-400.woff
|- fa-brands-400.woff2
|- fa-brands-400.svg
|- fa-brands-400.ttf
js
|- index.js
vite.config.js
...
In my tailwind.css, I'm importing the font:
#font-face{
font-family:"Font Awesome 5 Brands";
font-style:normal;
font-weight:400;
font-display:block;
src:url(../styles/fonts/font_awesome/fa-brands-400.eot);
src:url(../styles/fonts/font_awesome/fa-brands-400.eot?#iefix) format("embedded-opentype"),url( ../styles/fonts/font_awesome/fa-brands-400.woff2) format("woff2"),url(../styles/fonts/font_awesome/fa-brands-400.woff) format("woff"),url(../styles/fonts/font_awesome/fa-brands-400.ttf) format("truetype"),url(../styles/fonts/font_awesome/fa-brands-400 .svg#fontawesome) format("svg")
}
The problem, Vite copied the imported font files to my build folder and my font import now looks like this (in build/tailwind.css:
#font-face{
font-family:"Font Awesome 5 Brands";
font-style:normal;
font-weight:400;
font-display:block;
src:url(/fa-brands-400.eot);
src:url(/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(/fa-brands-400.woff2) format("woff2"),url(/fa-brands-400.woff) format("woff"),url(/fa-brands-400.ttf) format("truetype"),url(/fa-brands-400.svg#fontawesome) format("svg")
}
Is there a way to disable this? I just want Vite to bundle my JS and CSS, but don't include my assets.
My vite.config.js looks like this:
import postcssImport from "postcss-import"
import tailwindcssNesting from "tailwindcss/nesting"
import tailwindcss from "tailwindcss"
import autoprefixer from "autoprefixer"
import postcssScss from "postcss-scss"
import { defineConfig } from "vite"
export default defineConfig({
build: {
outDir: "build",
cssCodeSplit: true,
emptyOutDir: true,
minify: false,
assetsDir: "",
rollupOptions: {
input: {
index: "js/index.js",
tailwind: "styles/tailwind.css",
},
output: {
entryFileNames: "[name].js",
assetFileNames: "[name].[ext]",
},
},
},
css: {
postcss: {
syntax: postcssScss,
plugins: [postcssImport, tailwindcssNesting, tailwindcss, autoprefixer],
},
},
clearScreen: true,
publicDir: false,
})

I am facing a similar issue with a library build. I want to have an image relative to my css file, but default it is placed at the root and the reference in the css file is also to the root (just like in your problem). I did not find a perfect solution, but I was able to place the image in the same folder as the css file, where the css file also references the image in the same folder. I used the rollup config option output.assetFileNames for this. You can pass your own function and in that function you can add the complete path to the folder where you want to add the asset.
assetFileNames: (assetInfo: PreRenderedAsset): string => {
if (assetInfo.type === 'asset') {
return 'styles/fonts/[name][extname]';
}
else {
return '[name][extname]';
}
},
This will place the fonts in the build/styles/font folder. The references in the css will also be in this folder.
There is one caveat: The references will begin with '/', so they will be from the root of the domain. I have not found a solution for this.

Related

Multiple Tailwind CSS Configs

I am building a project using Laravel/Inertia/Vue and I am using Tailwind CSS.
I want to have separate admin.css and client.css files using tailwindcss 3.2 ability to have multiple config files:
./styles/admin.css
#config "./tailwind.admin.config.js"
#tailwind base;
#tailwind components;
#tailwind utilities;
but the problem is that Vite will build just app.css for me not the admin one
vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '#vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.js',
ssr: 'resources/js/ssr.js',
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
ssr: {
noExternal: ['#inertiajs/server'],
},
server: {
host: "localhost",
},
});
app.css is imported in app.js
I can not figure it out
Could you please help me?
I want to have separate admin.css and client.css files per each tailwindcss config file.
You can pass an array of input files to vite as follows:
input: ['resources/js/app.js','resources/css/admin.css','resources/css/client.css']
This should result in seperate output files in your build directory.
If you want to keep the css as javascript import you can create a second InertiaApp for the admin area:
Copy app.js and rename it like 'admin.js'
Change css import in admin.js to '/styles/admin.css'
Change your vite input to: input: ['resources/js/app.js','resources/js/admin.js']
Use a different blade layouts for the 'admin' area with reference to admin.js instead of app.js : #vite('resources/js/admin.js')
Thanks #dustin for your answer. Here are some more things:
I can split javascript application by defining multiple rootViews using inertia-laravel#0.3.2 in HandleInertiaRequests.php middleware:
public function rootView(Request $request)
{
if ($request->routeIs('admin.*')) {
return 'admin';
}
return 'app';
}
And have two different apps.
But do you think its a good approach to have two different apps?
I like the separation idea but is it the right way?
I Also have concerns about bundling and mixing in inertia and ssr, would it be a problem for that when you have two apps? I dont know anything about inertia's way of working
I was hoping there is some other method like creating a higher order component or something like that. I am very new to Vue world and I am still trying to learn.

How can I use fontawesome icons in a laravel application using vite?

I have installed #fortawesome/fontawesome-free package using npm. The latest Laravel application uses vite by default. I am unable to solve this issue. Any help would be much appreciated. My vite.config.js is
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { viteStaticCopy } from 'vite-plugin-static-copy';
export default defineConfig({
plugins: [
laravel([
'resources/css/app.css',
'resources/js/app.js',
'resources/admin/css/app.css',
'resources/admin/js/app.js',
'resources/css/glide.css',
'resources/js/glide.js',
'resources/js/Sortable.js',
'resources/js/tinymce.js',
'resources/sass/app.scss',
'resources/admin/sass/app.scss',
]),
{
name: 'blade',
handleHotUpdate({ file, server }) {
if (file.endsWith('.blade.php')) {
server.ws.send({
type: 'full-reload',
path: '*',
});
}
},
},
viteStaticCopy({
targets: [
{
src: 'node_modules/#fortawesome/fontawesome-free/webfonts',
dest: '',
},
],
}),
],
});
I imported fontawesome scss files in app.scss. My app.scss file contains
#import "#fortawesome/fontawesome-free/scss/fontawesome";
#import "#fortawesome/fontawesome-free/scss/brands";
#import "#fortawesome/fontawesome-free/scss/regular";
#import "#fortawesome/fontawesome-free/scss/solid";
#import "#fortawesome/fontawesome-free/scss/v4-shims";
I tried using a third party library https://github.com/sapphi-red/vite-plugin-static-copy to copy webfonts of fontawesome package. Is there a better way than this?
I solved it by first installing sass pre-processor:
npm install -D sass
after that I imported all fontawesome scss files into my app.js file:
import './bootstrap';
import '#fortawesome/fontawesome-free/scss/fontawesome.scss';
import '#fortawesome/fontawesome-free/scss/brands.scss';
import '#fortawesome/fontawesome-free/scss/regular.scss';
import '#fortawesome/fontawesome-free/scss/solid.scss';
import '#fortawesome/fontawesome-free/scss/v4-shims.scss';
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
It is quite easy if you are not adding it via npm. Copy entire fontawesome dir into resources dir (/resources/fontawesome), then declare variable in your scss file like (assuming you are doing it in a file inside /resources/sass:
$fa-font-path: '../fontawesome/webfonts';
and import fontawesome files:
#import '../fontawesome/scss/brands';
#import '../fontawesome/scss/solid';
#import '../fontawesome/scss/light';
#import '../fontawesome/scss/fontawesome';
Build script will copy files to your /public/build/assets dir and change urls and dev script will load them from your resources dir.

Vite does not build my #extend rules from bulma-scss

I'm having a build issue with the scss at-rule "extend" using Vite to build out a Vue3 component library using the bulma-scss NPM package.
Using Bluma buttons for example, I would like to import the bulma-scss button.scss file into my tag in my .vue file (or into the button.scss file and then import that into the script tag) like so:
<template/>
<script/>
...
<style lang="scss">
#import 'bulma-scss/elements/button';
</style>
When running $ vite build I get this error from Vite:
File: /Users/my-user/sites/component-library/node_modules/bulma-scss/elements/_button.scss
Error: The target selector was not found.
Use "#extend %control !optional" to avoid this error.
It is specifically this line in the bulma-scss package that it doesn't like (in this example) https://github.com/j1mc/bulma-scss/blob/master/elements/_button.scss#L71
it looks like I can get around this by adding the following preprocessor option to my storybook's vite configs:
css: {
preprocessorOptions: {
scss: {
additionalData: `#import "bulma-scss";`
}
},
},
But that would include the entirety of bulma-scss right? Ideally I would only import the things I need from bulma.
And here is my entire vite config file (sans the css preprocessorOptions)
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import {resolve} from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
name: 'lmsComponentLibrary',
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue',
},
},
},
},
resolve: {
alias: {
'bulma-scss/': require('path').join(__dirname, 'node_modules/bulma-scss/'),
}
},
});
I think the problem comes from the bulma-scss package itself. In the file that you are importing there is no %control placeholder. Even its import ../utilities/controls and ../utilities/mixins don't have that placeholder neither. So the error is expected here.
The %control is defined in bulma-scss/utilities/extends so you can fix the problem by importing that file. BUT, it will lead to another problem because in the _extends.scss there are some variables that are not defined. So you need to import all the file that contains these variables.
Luckily, the package has a file containing all the utility variables. So you just need to import it.
#import 'bulma-scss/utilities/all'; <-- Add this line
#import 'bulma-scss/elements/button';

How can I get Vue.js 2.0 typings for TypeScript working with Visual Studio?

I'm trying to get Vue.js 2.0 typings working with TypeScript in Visual Studio. Previously, I had used these typings from DefinitelyTyped, but they are for Vue.js 1.0 and thus don't match up. However, they did work just fine and let me work with the Vue type.
I've since transitioned to using the typing files that come with Vue.js releases (here). I have included them in my project in my ~/Scripts/typings/vue folder, but my project does not understand them.
I've gathered that these typing files are meant to be used via import/export possibly? There are no other typing files I am using that work this way, so I am not sure how to correctly implement the typings such that they are available globally to my project.
I have a sample solution that shows an example of what I've tried - download here from my github repo.
Here's the structure of my Scripts folder:
_references.d.ts contents
/// <reference path="typings/vue/index.d.ts" />
vue_test.ts contents
namespace Test
{
export class MyClass
{
public initialize()
{
var component = this.getComponent();
}
private getComponent(): Vue.Component
{
return Vue.component("test", {
template: "<div></div>",
props: ["test"],
methods: {
onClick: () =>
{
}
}
});
}
}
}
What I would expect is that I would have access to the Vue.Component namespace and other namespaces that are declared in typings/vue/index.d.ts, but this does not seem to be the case.
I did attempt to import the exported class into global, like this:
import * as _Vue from "./index";
declare global
{
export class Vue extends _Vue
{
}
}
However, this only allows me to access the root Vue class, and thus I cannot do things like specify Vue.Component as a type, or any other namespace beyond Vue.
Other information:
Visual Studio 2015
Vue.js version 2.2.1
TypeScript version 2.1
UPDATE after suggestions from #unional
Here is my new folder structure:
No more _references.d.ts, using tsconfig.json instead. The tsconfig.json file contains this:
{
"compilerOptions": {
"sourceMap": true
},
"include": [
"../../**/*.ts"
]
}
The above imports all .ts files in the project. The ~/Scripts/typings/custom-typings/vue.d.ts file contains the following:
export * from "vue"
export as namespace Vue
Visual Studio tells me Cannot find module 'vue', so my typings are still not functional, although the tsconfig.json file works (I added the jQuery typing to verify that).
Here is a link to the updated solution showing the new problems: [link]
With NPM
Drop down to the command line in your app's root directory to use NPM and the TypeScript command line interface.
If you do not already have a package.json file, then first run npm init.
Then to install vue.js, run npm install --save vue.
To install its types run npm install --save-dev #types/vue.
If you also lack a tsconfig.json file, then run tsc --init.
At that point, you will be able to build by running tsc.
Without NPM
Not using NPM is unconventional and will require a lot of manual work. Here is one of those manual approaches.
Download VueJS 2.1.1 from the GitHub repo. After extracting the archive,
Put the contents of dist into Scripts/vuejs directory,
Put the contents of typings into typings/vuejs directory,
Add a tsconfig.json file to your project's root that his this content.
tsconfig.json
{
"compilerOptions": {
// ....... other properties omitted
"typeRoots": [
"./typings/"
],
"target": "es5",
"lib": ["es2015", "dom", "es2015.promise" ]
}
}
Then, at the top of the file that will be using Vue, add a relative import statement.
import * as Vue from "../typings/vuejs";
interface MyComponent extends Vue {
message: string
onClick (): void
}
export default {
template: '<button #click="onClick">Click!</button>',
data: function () {
return {
message: 'Hello!'
}
},
methods: {
onClick: function () {
window.alert(this.message)
}
}
}
Example
Here is an updated version of your WebApplication1 example.
https://github.com/bigfont/StackOverflow/tree/master/TypeScriptVueJsTypes
See also:
https://v2.vuejs.org/v2/guide/typescript.html
https://github.com/vuejs/vue
I was able to use information from #unional's comment, but with a slight change:
I added this to my custom-vue.d.ts file:
import * as _Vue from 'vue';
export as namespace Vue;
export = _Vue;
Additionally, I had to create a package.json file with the following:
{
"dependencies": {
"vue": "^2.2.1"
}
}
Finally, I needed to add a node_modules folder at the same scope as my tsconfig.json file. It has the following:
+-- node_modules
| +-- vue
| | +-- package.json
| | +-- types
| | | +-- index.d.ts
| | | +-- options.d.ts
| | | +-- plugin.d.ts
| | | +-- vnode.d.ts
| | | +-- vue.d.ts
package.json simple contains:
{
"typings": "types/index.d.ts"
}
And things are now WORKING
Edit
Alternatively, I discovered I could avoid the whole node_modules thing by setting tsconfig.json's property for moduleResolution to Classic. After doing that, I changed my custom-vue.d.ts import to look like this:
import * as _Vue from "../vue/index";
Since the error is at compile time, No big problem in it. you can use this plugin to for faster development from here
Also, the code should be as
import Vue from 'vue'
import Component from 'vue-class-component'
// The #Component decorator indicates the class is a Vue component
#Component({
template: ''
})
export default class MyComponent extends Vue {
}
and so on. You can still use the vuejs inside your cshtml files.

using d3.js as an external in webpack

I'm using this tutorial to setup a React.js project with webpack. The webpack.config.js below is almost an exact copy (except that I'm using an app and 'dist' folder), and I am also adding d3.js as an external. Because React is added as an external it lets me do require('react') in any of my app files without including it in the bundle. I wish to do the same with d3.js and have installed it as a node_module, and listed it in the externals area of my webpack config, but when I do require('d3') i get an error message that it's not available.
How can I use d3 (or jQuery for that matter) as an external if I have it installed as a node_module?
this is my project setup
/app
/dist
/node_modules
package.json
webpack.config.js
module.exports = {
entry: './app/index.jsx',
output: {
path: './dist',
filename: 'bundle.js', //this is the default name, so you can skip it
//at this directory our bundle file will be available
//make sure port 8090 is used when launching webpack-dev-server
publicPath: 'http://localhost:8090/assets'
},
module: {
loaders: [
{
//tell webpack to use jsx-loader for all *.jsx files
test: /\.jsx$/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony'
}
]
},
externals: {
//don't bundle the 'react' npm package with our bundle.js
//but get it from a global 'React' variable
'react': 'React',
'd3': 'd3'
},
resolve: {
modulesDirectories: ['app', 'node_modules'],
extensions: ['', '.js', '.jsx']
}
}
I know this question has been open a while, but hopefully this answer is still useful!
If you have installed d3 (or jQuery) as a node_module, you can use the webpack ProvidePlugin to tie an arbitrary key to a module.
The key will be then be available to require anywhere in your webpack app.
E.g. webpack.config.js
{
...lots of webpack config here...
...
plugins: [
new webpack.ProvidePlugin({
d3: 'd3',
$: 'jquery'
})
]
...
}
Then in my-file.js
var d3 = require('d3')
Hope that helps!

Resources