I setup my Vite config to split certain assets files to specific folders.
assets
animations
fonts
images
scripts
styles
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
let extType = assetInfo.name.split('.').at(1);
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
extType = 'images';
} else if (/css|sass|scss/i.test(extType)) {
extType = 'styles';
} else if (/woff|woff2|eot|ttf|otf/i.test(extType)) {
extType = 'fonts';
} else if (/json/.test(extType)) {
extType = 'animations';
}
return `${extType}/[name][extname]`;
},
entryFileNames: `scripts/[name].js`,
chunkFileNames: `scripts/[name].js`,
sourcemap: true
}
},
The problem are not JSONs files are not outputted to animations folder. This folder is not created at all.
I setup simple stackblitz to outline my local https://stackblitz.com/edit/node-vs9rej?file=vite.config.js
When I import json from '#rollup/plugin-json';
and add json() to plugin I get an error
[plugin:json] Could not parse JSON file
What am I doing wrong?
#rollup/plugin-json converts JSON files into modules, which Vite already supports out of the box, so that plugin is not needed.
Since Vite converts .json imports into JavaScript modules (not assets), you won't see those .json files in the build output, and the rollupOptions.output config you have would not have the desired effect. Instead, you'd see the JSON content of those files in the .js bundle.
Possible Solution
One way to preserve animations/*.json as static assets is to move them into public/ and have your app fetch the files at runtime.
To output the .json files to <BUILD_OUTPUT_DIR>/animations/, put them in public/animations/. The files would then be reachable at runtime from: <BASE_URL> + '/animations/<FILENAME>.json', where <BASE_URL> can be replaced with import.meta.env.BASE_URL. For instance, to fetch animations/act.json at runtime:
// scripts/_animation.js
fetch(import.meta.env.BASE_URL + '/animations/act.json')
.then(res => res.json())
.then(json => {
console.log('animation', json)
})
.catch(err => {
console.warn('cannot fetch animation', err)
});
It's unclear how you intend to use those files because your demo does nothing with them after importing, but the above should work in most use cases.
demo
Related
First of all, I wanna say that I've started using Vite awhile ago and I'm no Vite expert in any shape or form.
Now, about my problem: I'm working on a Chrome Extension which requires me to have the files generated in the /dist folder. That works excellent using vite build. But, if I try to use only vite (to get the benefits of HMR), no files get generated in the /dist folder. So I have no way to load the Chrome Extension.
If anyone has faced similar issues, or knows a config that I've overlooked, feel free to share it here.
Thanks!
With this small plugin you will get a build after each hot module reload event :
In a file hot-build.ts :
/**
* Custom Hot Reloading Plugin
* Start `vite build` on Hot Module Reload
*/
import { build } from 'vite'
export default function HotBuild() {
let bundling = false
const hmrBuild = async () => {
bundling = true
await build({'build': { outDir: './hot-dist'}}) // <--- you can give a custom config here or remove it to use default options
};
return {
name: 'hot-build',
enforce: "pre",
// HMR
handleHotUpdate({ file, server }) {
if (!bundling) {
console.log(`hot vite build starting...`)
hmrBuild()
.then(() => {
bundling = false
console.log(`hot vite build finished`)
})
}
return []
}
}
}
then in vite.config.js :
import HotBuild from './hot-build'
// vite config
{
plugins: [
HotBuild()
],
}
I want to configure the following set up for developing a react app and it's components with a possibility of css theming.
Each React component will have a separate js file, and will
explicitly import its corresponding "component.css" file.
The css explicitly imported in the js file will have the essential none themed css for that component.
At compile time I want Webpack to be configured with a theme name, and directories where it needs to look for the theme files.
During the loading of component js files, the compiler will detect the .css imports in the form of "component.css", for each of those imports it will look for a theme .css file in the form of "component.themename.css" in the configured directories and subdirectories.
If a theme file is found the compiler will add the import for that file into the js file being loaded.
With the above set up I want to be able to define theme css files for each of my components separately and then use the appropriate theme file according to a theme of my choosing.
Is there anything already available that would achieve something like this? What's the best way of implementing something like this? A loader? a plugin?
I have managed to achieve the above quite nicely with a custom css webpack loader and plugin.
The plugin searches for available theme files in the given directories.
The loader is added to the start of the loader chain. It is configured with a theme name and a reference to an object containing theme files found by the plugin.
For every css file imported it looks for a theme file with the same name and a .theme. suffix. Eg. for component.css it will look for component.theme.css in the given directories.
If it finds a theme .css file it appends it's contents to the css being loaded, and adds the theme file to the webpack watched dependencies.
Here's the code to achieve this:
webpack.config.js
const themeLoaderPlugin = new ThemeLoaderPlugin({theme: "themeName", dirs: ["dir/to/search/for/themefiles"] });
const css = {
test: /\.(css|s[ac]ss)$/,
use: ['style-loader', 'css-loader',
{
loader: path.resolve('/path/to/loader.js'),
options: {
theme: "themeName",
filesContainer: themeLoaderPlugin.getState()
}
}]
};
const config = {
...
plugins: [
themeLoaderPlugin
]
}
loader code:
const loaderUtils = require('loader-utils')
const fs = require('fs')
const path = require('path')
module.exports = function(source) {
let options = loaderUtils.getOptions(this);
let themeName = options.theme;
let files = options.filesContainer.files;
let fileName = this.resourcePath.match(/.*(\/|\\)(.*)\..*/)[2];
let themeFileName = fileName + "." + themeName + ".";
for (const file of files) {
if(file.indexOf(themeFileName) >= 0){
let contents = fs.readFileSync(file);
source = source + "\n" + contents.toString("UTF-8");
this.dependency(path.resolve(file));
}
}
return source;
};
Plugin code:
const glob = require('fast-glob')
module.exports = class ThemeLoaderPlugin {
constructor(options){
this.options = options;
this.state = {};
}
getState(){
return this.state;
}
refreshFiles() {
this.state.files = getThemeFiles(this.options.dirs, this.options.theme);
}
apply(compiler){
compiler.hooks.beforeRun.tap("ThemeFilesScanPlugin", ()=>{
this.refreshFiles();
});
compiler.hooks.watchRun.tap("ThemeFilesScanPlugin", () =>{
this.refreshFiles();
});
}
};
function getThemeFiles(paths, themeName){
let res = [];
for (const path of paths) {
let options = {
cwd:path,
ignore: "**/node_modules/**",
absolute: true
};
res.push(...glob.sync("**/*." + themeName +".*", options));
}
return res;
}
When using Nuxt, I ask questions.
When I distributed the site I built, the cache problem caused it to malfunction.
There are two cases below. Is there any way to solve them?
If built, the file names of js and css will be renamed to hash values, but it was not reflected by viewing old cache in browser.
Create applications using vue-native webview The webview in the application looked up the old cache. To apply the changed js, css, how do I remove the cache from the past?
https://github.com/nuxt/nuxt.js/issues/4764#issuecomment-713469389
Implementation of this one:
Add a plugin filename route.client.js
Include in nuxt.config.json
function getClientAppVersion() {
return localStorage.getItem('APP_VERSION') ?? 0
}
function setClientAppVersion(version) {
return localStorage.setItem('APP_VERSION', version)
}
export default ({ app }) => {
app.router.afterEach((to, from) => {
fetch("/version.json").then((serverPromise) =>
serverPromise.json().then((response) => {
const latestVersion = response.version
const clientStoredVersion = getClientAppVersion()
if (clientStoredVersion != latestVersion) {
window.location.reload(true)
setClientAppVersion(latestVersion)
}
else return
}))
})}
Add version.jon file
{
"version": "9.1"
}
I want to use the library ebnf from NPM and create a bundle using rollup. Since the ebnf is installed to node_modules I also use the rollup plugin rollup-plugin-node-resolve.
The problem is that ebnf contains the code require('..') which - in my case - is resolved to dist in my case. Thus it seems .. is interpreted relative to the output file instead of being relative to the source file.
This is my rollup.config.js (taken from my test repo jneuendorf/rollup-broken-resolve):
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'cjs'
},
// name: 'MyModule',
plugins: [
resolve(),
commonjs(),
]
}
Is this a problem in rollup-plugin-node-resolve or am I doing something wrong?
Since some of the external libraries needed will still be available only as Common.js modules, you could also convert them to ES-Modules:
"Since most packages in your node_modules folder are probably legacy CommonJS rather than JavaScript modules, you may need to use rollup-plugin-commonjs"
https://github.com/rollup/rollup-plugin-commonjs
"Convert CommonJS modules to ES6, so they can be included in a Rollup bundle"
Just in case someone searching this issue on how to make #rollup/plugin-node-resolve (previously was rollup-plugin-node-resolve) to work with relative path. I just found the solution:
function resolve(file, origin) {
// Your way to resolve local include path
}
function pathResolve(options) {
return {
resolveId: function(file, origin) {
// Your local include path must either starts with `./` or `../`
if (file.startsWith('./') || file.startsWith('../')) {
// Return an absolute include path
return resolve(file, origin);
}
return null; // Continue to the next plugins!
}
};
}
Here is how to combine it with #rollup/plugin-node-resolve:
import {nodeResolve} from '#rollup/plugin-node-resolve';
function pathResolve(options) { /* ... */ }
export default {
// ...
plugins: [pathResolve(), nodeResolve()]
};
How should one package the HTML templates (aka 'partials') in an Angular.js app when it is concatenated + minified for distribution? Is there a good way of including them in that single file, or should I zip the folder which contains the main.js, /templates/*.html and /styles/app.css subdirectories?
The Require.js optimizer compresses all the JS files to a single file myapp.min.js that is suitable for distribution, but the HTML files are still referenced as individual files.
As background, the code is in a Node.js server:
public/
/app/main.js
/app/app.js
/app/directives/*.js
/app/filters/*.js
/app/factories/*.js
/app/other/*.js
/app/templates/*.html
After running r.js, all the files in public/app/** have optimized twins located in a different directory public/build/**. But the browser still looks for the templates in their original location, /app/templates/*.html.
So presumably the client would have to put them in that same directory, which seems like an unfair constraint.
Minifying RequireJS Javascript codebase to a single file
You have to use the templates through the text! plugin of RequireJS. E.g. for a directive:
define(["text!app/templates/a.html", "myAngularModule"],
function(template, myAngularModule) {
myAngularModule.directive("theDirective", function() {
return {
template: template, // NOTE HERE
...
};
});
});
Or a route:
define(["text!app/templates/a.html", "myAngularModule"],
function(template_a, myAngularModule) {
myAngularModule.config(function($routeProvider) {
$routeProvider.when("some/path", {
template: template_a, // NOTE HERE
...
});
...
});
});
Alternative, using templateUrl (just in case it is needed):
define(["text!app/templates/a.html", "myAngularModule"],
function(template_a, myAngularModule) {
myAngularModule.config(function($routeProvider) {
$routeProvider.when("some/path", {
templateUrl: "app/templates/a.html", // can be any value actually
...
});
...
});
myAngularModule.run(function($templateCache) {
$templateCache.put(
"app/templates/a.html", // NAME MUST MATCH NAME ABOVE
template_a
);
});
});