How add not imported image to output build with vite? - vite

I have an app folder with some images that are used by the external script and I need to include those images in the dist build folder.
I tried to log files that go to output and those images are not included. I tried to add assetsInclude property but seems that property is not for that purpose.
How can I include some specific images in dist folder that aren't imported explicitly ?
Here is my vite.config.js file.
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
assetsInclude: ['/app/images/externalImage.png'],
build: {
emptyOutDir: true,
rollupOptions: {
output: {
dir: './dist',
assetFileNames: (asset) => {
console.log(parse(asset.name).name);
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});

In my js file which is included as a module inside the HTML file, I added string that you can see below. Here is details of how to expose the current module URL.
app/js/app.js
new URL("../images/src/externalImage.png", import.meta.url);
Also changed a bit config - added outDir prop:
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
build: {
outDir: '../dist',
emptyOutDir: true,
rollupOptions: {
output: {
assetFileNames: (asset) => {
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});

Related

Vite how to prevent ,js filename change to other format

I have config something like this
import { defineConfig } from "vite";
export default defineConfig({
build: {
lib: {
entry: "src/main.ts",
name: "main",
fileName: "main",
formats: ["cjs"],
},
outDir: ".",
rollupOptions: {
external: ["obsidian"],
output: {
globals: {
obsidian: "obsidian",
},
},
},
},
});
After build command it creates main.cjs file, I want it to be just main.js.
How can I achieve this.

How to override the rollup output.format setting in vite?

I'm trying to solve the Vite build error I get:
RollupError: Invalid value "iife" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.
The file name reported with this error points to
my web worker code, so I assumed that this setting belongs to the worker section in vite.config.ts:
import { defineConfig } from "vite";
import preact from "#preact/preset-vite";
import basicSsl from "#vitejs/plugin-basic-ssl";
import { NodeGlobalsPolyfillPlugin } from "#esbuild-plugins/node-globals-polyfill";
import { NodeModulesPolyfillPlugin } from "#esbuild-plugins/node-modules-polyfill";
import rollupNodePolyFill from "rollup-plugin-node-polyfills";
export default defineConfig({
plugins: [
preact(),
basicSsl(),
],
server: {
port: 3001,
https: true,
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
NodeModulesPolyfillPlugin(),
],
},
},
worker: {
rollupOptions: {
output: {
format: "esm",
},
},
},
build: {
rollupOptions: {
plugins: [
// Enable rollup polyfills plugin
// used during production bundling
rollupNodePolyFill(),
],
output: {
format: "esm",
},
},
},
});
Additionally, I set the output format in the build rollup options. However, neither of the two settings are applied and I still get the said error.
What is the correct way to change the rollup output format setting in Vite?
The worker output format must be specified directly in the worker config key, not its rollup options:
import { defineConfig } from "vite";
import preact from "#preact/preset-vite";
import basicSsl from "#vitejs/plugin-basic-ssl";
import { NodeGlobalsPolyfillPlugin } from "#esbuild-plugins/node-globals-polyfill";
import { NodeModulesPolyfillPlugin } from "#esbuild-plugins/node-modules-polyfill";
import rollupNodePolyFill from "rollup-plugin-node-polyfills";
export default defineConfig({
plugins: [
preact(),
basicSsl(),
],
server: {
port: 3001,
https: true,
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
NodeModulesPolyfillPlugin(),
],
},
},
worker: {
format: "es",
},
build: {
rollupOptions: {
plugins: [
// Enable rollup polyfills plugin
// used during production bundling
rollupNodePolyFill(),
],
output: {
format: "esm",
},
},
},
});

How to wrap Vite build in IIFE and still have all the dependencies bundled into a single file?

I'm building a chrome extension using Vite as my build tool. The main problem is during minification and mangling there are a lot of global variables created. After injecting my script to the page they conflict with already defined variables on window object.
I imagine the perfect solution would be to have my entire script wrapped in IIFE. I tried using esbuild.format = 'iife'. The resulting build is in fact wrapped in IIFE, however all the imports are not inlined. Instead resulting script is like 15 lines long with a bunch of require statements, which obviously does not work in the browser.
This is my config file:
export default defineConfig({
plugins: [
vue(),
],
esbuild: {
format: 'iife',
},
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, './src/web/index.ts'),
output: {
dir: resolve(__dirname, './dist'),
entryFileNames: 'web.js',
assetFileNames: 'style.css',
},
},
},
resolve: {
alias: {
'#': resolve(__dirname, './src'),
},
},
});
I'm currently using this hack so to say to wrap my build in IIFE (for this I removed the esbuild.format option).
Hey I am doing the exact same thing! And I also noticed the unminified variables and functions can clash with random code in a webpage.
From what I researched myself on this topic, you shouldn't change esbuild build options with Vite as that will prevent Rollup from transforming the output. Instead, you should use format: 'iife' in the rollupOptions of your vite.config. However, in my case (and yours I believe), I have to output multiple bundles since the extension code can't share modules amongst each other. Which will crash when you set the format to 'iife' due to:
Invalid value for option "output.inlineDynamicImports" - multiple inputs are not supported when "output.inlineDynamicImports" is true.
The only solution in my case seems to be to either use multiple vite.configs (I already have two) for each of my bundle with single input entry point and format as 'iife'. Or, as you did, just write the self-invoking function yourself with some hacky script. Seems though there aren't any perfect solutions as of now.
EDIT: Okay, got it working. This is my vite.config.ts (the project):
import { defineConfig } from 'vite'
import { svelte } from '#sveltejs/vite-plugin-svelte'
import tsconfigPaths from 'vite-tsconfig-paths'
import path from 'path'
/** #type {import('vite').UserConfig} */
export default defineConfig({
plugins: [svelte({}), tsconfigPaths()],
build: {
minify: false,
rollupOptions: {
output: {
chunkFileNames: '[name].js',
entryFileNames: '[name].js'
},
input: {
inject: path.resolve('./src/inject.ts'),
proxy: path.resolve('./src/proxy.ts'),
'pop-up': path.resolve('./pop-up.html')
},
plugins: [
{
name: 'wrap-in-iife',
generateBundle(outputOptions, bundle) {
Object.keys(bundle).forEach((fileName) => {
const file = bundle[fileName]
if (fileName.slice(-3) === '.js' && 'code' in file) {
file.code = `(() => {\n${file.code}})()`
}
})
}
}
]
}
}
})
Okay, I made it working with this config:
export default defineConfig({
plugins: [
vue(),
],
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, './src/web/index.ts'),
output: {
format: 'iife',
dir: resolve(__dirname, './dist'),
entryFileNames: 'web.js',
assetFileNames: 'style.css',
},
},
},
resolve: {
alias: {
'#': resolve(__dirname, './src'),
},
},
});
They key part is format: 'iife' inside build.rollupOptions.output.

How to read the .ts configuration file from the root of the project in the npm package (ESM)

How can I read the configuration file (e.g. mypkg.config.ts) from the root of the project in my npm module built on ESM?
I found this, and figured out how to do it for .json, but not for .ts.
After a few hours of searching, I found what I needed in the sources of Vite.
All you have to do is convert your configuration file into JavaScript using esbuild for example, and then import it using:
const config = await import(`file://${absolutePathToTranspiledConfig}`)
And then just delete the generated JavaScript file.
Specifically, Vite uses the following transpilation script:
await build({
entryPoints: [/*path to config with .ts extension*/],
bundle: true,
minify: true,
platform: 'node',
outfile: /*path to transpiled config*/,
sourcemap: 'inline',
metafile: true,
format: 'esm',
plugins: [
{
name: 'externalize-deps',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
const id = args.path
if (id[0] !== '.' && !path.isAbsolute(id)) {
return {
external: true
}
}
})
}
},
{
name: 'replace-import-meta',
setup(build) {
build.onLoad({ filter: /\.[jt]s$/ }, async args => {
const contents = await fs.readFile(args.path, 'utf8')
return {
loader: args.path.endsWith('.ts') ? 'ts' : 'js',
contents: contents
.replace(
/\bimport\.meta\.url\b/g,
JSON.stringify(`file://${args.path}`)
)
.replace(
/\b__dirname\b/g,
JSON.stringify(path.dirname(args.path))
)
.replace(/\b__filename\b/g, JSON.stringify(args.path))
}
})
}
}
]
})

React's Uncaught Error: addComponentAsRefTo after building with webpack

I'm trying to build this package:
https://github.com/searchkit/searchkit/ (version v0.10.1)
with webpack and use this with my modules:
node v6.1.0
npm v3.8.6
Build strategy:
fetch repository from github
npm install
npm run build
inside /node_modules/
nothing special is done.
But after trying to use this module withun my components I get those cases.
Case is that if I build with:
searchkit/src/core/react/SearchkitProvider.tsx
import * as React from "react";
import {SearchkitManager} from "../SearchkitManager"
export interface SearchkitProps {
searchkit:SearchkitManager
children?:any
}
export class SearchkitProvider extends React.Component<SearchkitProps,any> {
static childContextTypes = {
searchkit:React.PropTypes.instanceOf(SearchkitManager)
}
static propTypes = {
searchkit:React.PropTypes.instanceOf(SearchkitManager).isRequired,
children:React.PropTypes.element.isRequired
}
componentWillMount() {
this.props.searchkit.setupListeners()
}
componentDidMount(){
this.props.searchkit.completeRegistration()
}
componentWillUnmount(){
this.props.searchkit.unlistenHistory()
}
getChildContext(){
return {searchkit:this.props.searchkit}
}
render(){
return (
<div>IT DOES WORK!!</div>
);
}
}
using by
class Listing extends React.Component {
render() {
return (
<div>
<SearchkitProvider searchkit={searchkit}>
<div></div>
</SearchkitProvider>
</div>
);
}
}
It DOES work properly with proper response, but If I change module's source to:
export class SearchkitProvider extends React.Component<SearchkitProps,any> {
(...)
render(){
return (
<div><input ref="REF" /></div>
);
}
}
it throws this error Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded.
I'm not really sure what dependency is made while I'm doing that kind of change ? Should I look for duplicated React instances even though it's working when I'm not using input with ref ?
Webpack.config.js:
const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const copyrightBanner = require("fs").readFileSync("./COPYRIGHT", "utf-8")
const autoprefixer = require('autoprefixer')
module.exports = {
entry: {
"ignore":['./theming/index.ts'],
"bundle":['./src/index.ts']
},
output: {
path: path.join(__dirname, 'release'),
filename: '[name].js',
library:["Searchkit"],
libraryTarget:"umd",
publicPath: '',
css: 'theme.css'
},
resolve: {
extensions:[".js", ".ts", ".tsx","", ".webpack.js", ".web.js", ".scss"],
alias: { react: path.resolve('../react') }
},
postcss: function () {
return [autoprefixer]
},
plugins: [
new webpack.BannerPlugin(copyrightBanner, {entryOnly:true}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new ExtractTextPlugin("theme.css", {allChunks:true}),
new webpack.optimize.UglifyJsPlugin({
mangle: {
except: ['require', 'export', '$super']
},
compress: {
warnings: false,
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true
}
})
],
externals: {
"react": "React",
"react-dom":"ReactDOM"
},
module: {
loaders: [
{
test: /\.tsx?$/,
loaders: ['ts'],
include: [path.join(__dirname, 'src'),path.join(__dirname, 'theming')]
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(require.resolve("style-loader"),require.resolve("css-loader")+"!"+require.resolve("postcss-loader")+"!"+require.resolve("sass-loader")),
include: path.join(__dirname, 'theming')
},
{
test: /\.(jpg|png|svg)$/,
loaders: [
'file-loader?name=[path][name].[ext]'
],
include: path.join(__dirname, 'theming')
}
]
}
};
npm ls react:
├── react#0.14.8
└─┬ UNMET PEER DEPENDENCY searchkit#0.10.1
└── react#0.14.8
npm ERR! peer dep missing: searchkit#0.9.x, required by searchkit-multiselect#0.0.1

Resources