@vctrl/hooks 0.0.8 → 0.0.9-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@nx/react/babel",
5
+ {
6
+ "runtime": "automatic",
7
+ "useBuiltIns": "usage"
8
+ }
9
+ ]
10
+ ],
11
+ "plugins": []
12
+ }
package/.eslintrc.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": ["plugin:@nx/react", "../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7
+ "rules": {}
8
+ },
9
+ {
10
+ "files": ["*.ts", "*.tsx"],
11
+ "rules": {}
12
+ },
13
+ {
14
+ "files": ["*.js", "*.jsx"],
15
+ "rules": {}
16
+ }
17
+ ]
18
+ }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.8",
2
+ "version": "0.0.9-2",
3
3
  "name": "@vctrl/hooks",
4
4
  "description": "vctrl/hooks is a React hooks package designed to simplify 3D model loading and management within React applications. It's part of the vectreal-core ecosystem and is primarily used in the vctrl/viewer React component and the official website application.",
5
5
  "bugs": {
@@ -34,9 +34,6 @@
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "files": [
38
- "."
39
- ],
40
37
  "exports": {
41
38
  "./use-load-model": {
42
39
  "import": "./use-load-model.es.js",
package/project.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "vctrl/hooks",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/hooks/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "build": {
9
+ "executor": "@nx/vite:build",
10
+ "options": {
11
+ "outputPath": "dist/packages/vctrl/hooks",
12
+ "configFile": "packages/hooks/vite.config.ts"
13
+ }
14
+ }
15
+ }
16
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './use-load-model';
@@ -0,0 +1,29 @@
1
+ import { EventData, EventHandler, EventTypes } from './types';
2
+
3
+ const listeners = {} as Record<EventTypes, EventHandler<EventTypes>[]>;
4
+ const eventSystem = {
5
+ emit<T extends EventTypes>(event: T, data: EventData[T]): void {
6
+ const handlers = listeners[event];
7
+ if (handlers) {
8
+ handlers.forEach((handler) => handler(data));
9
+ }
10
+ },
11
+
12
+ on<T extends EventTypes>(event: T, handler: EventHandler<T>): void {
13
+ if (!listeners[event]) {
14
+ listeners[event] = [];
15
+ }
16
+ listeners[event].push(handler as EventHandler<EventTypes>);
17
+ },
18
+
19
+ off<T extends EventTypes>(event: T, handler: EventHandler<T>): void {
20
+ const handlers = listeners[event];
21
+ if (handlers) {
22
+ listeners[event] = handlers.filter(
23
+ (h) => h !== handler,
24
+ ) as EventHandler<EventTypes>[];
25
+ }
26
+ },
27
+ };
28
+
29
+ export default eventSystem;
@@ -0,0 +1,2 @@
1
+ export { default as useLoadGltf } from './use-load-gltf';
2
+ export { default as useLoadBinary } from './use-load-binary';
@@ -0,0 +1,74 @@
1
+ import { useCallback } from 'react';
2
+
3
+ import { Action, ModelFileTypes } from '../types';
4
+ import { createGltfLoader, createUsdzLoader } from '../loaders';
5
+
6
+ /**
7
+ * Hook to load binary files
8
+ *
9
+ * @param dispatch - The dispatch function from the useReducer hook
10
+ * @returns An object containing the loadBinary function
11
+ */
12
+ function useLoadBinary(dispatch: React.Dispatch<Action>) {
13
+ /**
14
+ * Function to read binary files
15
+ *
16
+ * @param file - The binary file to read
17
+ * @param fileType - The type of file to read
18
+ * @param onProgress - The function to call when progress is made
19
+ * @returns {void}
20
+ */
21
+ const loadBinary = useCallback(
22
+ (file: File, fileType: ModelFileTypes, onProgress: () => void) => {
23
+ const reader = new FileReader();
24
+
25
+ reader.onload = async (event: ProgressEvent<FileReader>) => {
26
+ if (event.target?.result) {
27
+ const arrayBuffer = event.target.result as ArrayBuffer;
28
+
29
+ if (fileType === ModelFileTypes.glb) {
30
+ const gltfLoader = createGltfLoader();
31
+
32
+ gltfLoader.parse(arrayBuffer, '', (gltf) => {
33
+ dispatch({
34
+ type: 'SET_FILE',
35
+ payload: {
36
+ model: gltf.scene,
37
+ type: ModelFileTypes.glb,
38
+ name: file.name,
39
+ },
40
+ });
41
+ });
42
+ } else if (fileType === ModelFileTypes.usdz) {
43
+ const usdzLoader = createUsdzLoader();
44
+ const model = usdzLoader.parse(arrayBuffer);
45
+
46
+ dispatch({
47
+ type: 'SET_FILE',
48
+ payload: {
49
+ model: model,
50
+ type: ModelFileTypes.usdz,
51
+ name: file.name,
52
+ },
53
+ });
54
+ }
55
+
56
+ onProgress(); // Call progress callback when binary file is loaded
57
+ dispatch({ type: 'SET_FILE_LOADING', payload: false });
58
+ }
59
+ };
60
+
61
+ reader.onerror = (error) => {
62
+ console.error('Error reading file:', error);
63
+ dispatch({ type: 'SET_FILE_LOADING', payload: false });
64
+ };
65
+
66
+ reader.readAsArrayBuffer(file);
67
+ },
68
+ [dispatch],
69
+ );
70
+
71
+ return { loadBinary };
72
+ }
73
+
74
+ export default useLoadBinary;
@@ -0,0 +1,115 @@
1
+ import { useCallback } from 'react';
2
+
3
+ import { Action, ModelFileTypes, ReducedGltf } from '../types';
4
+ import { arrayBufferToBase64 } from '../utils';
5
+ import { createGltfLoader } from '../loaders';
6
+
7
+ function useLoadGltf(dispatch: React.Dispatch<Action>) {
8
+ const embedExternalResources = useCallback(
9
+ async (
10
+ gltfContent: ReducedGltf,
11
+ otherFiles: File[],
12
+ onProgress: (progress: number) => void,
13
+ ) => {
14
+ const fileMap = new Map(otherFiles.map((file) => [file.name, file]));
15
+ const totalFiles =
16
+ (gltfContent.buffers?.length || 0) + (gltfContent.images?.length || 0);
17
+ let processedFiles = 0;
18
+
19
+ const updateProgress = () => {
20
+ processedFiles++;
21
+ onProgress((processedFiles / totalFiles) * 100);
22
+ };
23
+
24
+ // Embed buffers
25
+ if (gltfContent.buffers) {
26
+ for (let i = 0; i < gltfContent.buffers.length; i++) {
27
+ const buffer = gltfContent.buffers[i];
28
+ if (!buffer.uri || buffer.uri.startsWith('data:')) {
29
+ updateProgress();
30
+ continue;
31
+ }
32
+
33
+ const fileName = buffer.uri.split('/').pop() || '';
34
+ const file = fileMap.get(fileName);
35
+ if (file) {
36
+ const arrayBuffer = await file.arrayBuffer();
37
+ const base64 = await arrayBufferToBase64(arrayBuffer);
38
+ buffer.uri = `data:application/octet-stream;base64,${base64}`;
39
+ }
40
+ updateProgress();
41
+ }
42
+ }
43
+
44
+ // Embed images
45
+ if (gltfContent.images) {
46
+ for (let i = 0; i < gltfContent.images.length; i++) {
47
+ const image = gltfContent.images[i];
48
+ if (!image.uri || image.uri.startsWith('data:')) {
49
+ updateProgress();
50
+ continue;
51
+ }
52
+
53
+ const fileName = image.uri.split('/').pop() || '';
54
+ const file = fileMap.get(fileName);
55
+ if (file) {
56
+ const arrayBuffer = await file.arrayBuffer();
57
+ const base64 = await arrayBufferToBase64(arrayBuffer);
58
+ const mimeType = file.type || 'image/png';
59
+ image.uri = `data:${mimeType};base64,${base64}`;
60
+ }
61
+ updateProgress();
62
+ }
63
+ }
64
+
65
+ return gltfContent;
66
+ },
67
+ [],
68
+ );
69
+
70
+ const loadGltf = useCallback(
71
+ (
72
+ gltfFile: File,
73
+ otherFiles: File[],
74
+ onProgress: (progress: number) => void,
75
+ ) => {
76
+ const reader = new FileReader();
77
+ reader.onload = async (e) => {
78
+ const gltfContent = JSON.parse(e.target?.result as string);
79
+ onProgress(10); // Initial progress after parsing GLTF
80
+
81
+ const modifiedGLTF = await embedExternalResources(
82
+ gltfContent,
83
+ otherFiles,
84
+ (embeddingProgress) => {
85
+ // Map embedding progress to 10-90% range
86
+ onProgress(10 + embeddingProgress * 0.8);
87
+ },
88
+ );
89
+
90
+ const gltfLoader = createGltfLoader();
91
+
92
+ gltfLoader.parse(JSON.stringify(modifiedGLTF), '', (gltf) => {
93
+ dispatch({
94
+ type: 'SET_FILE',
95
+ payload: {
96
+ model: gltf.scene,
97
+ type: ModelFileTypes.gltf,
98
+ name: gltfFile.name,
99
+ },
100
+ });
101
+ });
102
+
103
+ onProgress(100); // Final progress
104
+ dispatch({ type: 'SET_FILE_LOADING', payload: false });
105
+ };
106
+
107
+ reader.readAsText(gltfFile);
108
+ },
109
+ [dispatch, embedExternalResources],
110
+ );
111
+
112
+ return { loadGltf };
113
+ }
114
+
115
+ export default useLoadGltf;
@@ -0,0 +1,3 @@
1
+ export { default as useLoadModel } from './use-load-model';
2
+ export { type ModelFile, ModelFileTypes } from './types';
3
+ export * from './model-context';
@@ -0,0 +1,20 @@
1
+ import { WebGLRenderer } from 'three';
2
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
3
+ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
4
+ import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader';
5
+
6
+ function createGltfLoader() {
7
+ const dracoLoader = new DRACOLoader();
8
+ dracoLoader.setDecoderPath('/draco/');
9
+
10
+ const ktxLoader = new KTX2Loader();
11
+ ktxLoader.setTranscoderPath('/draco/');
12
+
13
+ const gltfLoader = new GLTFLoader()
14
+ .setDRACOLoader(dracoLoader)
15
+ .setKTX2Loader(ktxLoader.detectSupport(new WebGLRenderer()));
16
+
17
+ return gltfLoader;
18
+ }
19
+
20
+ export default createGltfLoader;
@@ -0,0 +1,9 @@
1
+ import { USDZLoader } from 'three/examples/jsm/loaders/USDZLoader';
2
+
3
+ function createUsdzLoader() {
4
+ const usdzLoader = new USDZLoader();
5
+
6
+ return usdzLoader;
7
+ }
8
+
9
+ export default createUsdzLoader;
@@ -0,0 +1,2 @@
1
+ export { default as createGltfLoader } from './create-gltf-loader';
2
+ export { default as createUsdzLoader } from './create-usdz-loader';
@@ -0,0 +1,18 @@
1
+ import { createContext, useContext } from 'react';
2
+ import useLoadModel from './use-load-model';
3
+
4
+ const ModelContext = createContext({} as ReturnType<typeof useLoadModel>);
5
+
6
+ const ModelProvider = ({ children }: React.PropsWithChildren) => {
7
+ const value = useLoadModel();
8
+
9
+ return (
10
+ <ModelContext.Provider value={value}>{children}</ModelContext.Provider>
11
+ );
12
+ };
13
+
14
+ const useModelContext = () => {
15
+ return useContext(ModelContext);
16
+ };
17
+
18
+ export { ModelContext, ModelProvider, useModelContext };
@@ -0,0 +1,33 @@
1
+ import { Action, ModelFileTypes, State } from './types';
2
+
3
+ // Initial state
4
+ export const initialState: State = {
5
+ file: null,
6
+ isFileLoading: false,
7
+ progress: 0,
8
+ supportedFileTypes: Object.values(ModelFileTypes),
9
+ };
10
+
11
+ /**
12
+ * Reducer function for the useReadModelFiles hook
13
+ *
14
+ * @param state - The current state of the reducer
15
+ * @param action - The action to be performed
16
+ * @returns The updated state
17
+ */
18
+ function reducer(state: State, action: Action): State {
19
+ switch (action.type) {
20
+ case 'SET_FILE':
21
+ return { ...state, file: action.payload };
22
+ case 'SET_FILE_LOADING':
23
+ return { ...state, isFileLoading: action.payload };
24
+ case 'SET_PROGRESS':
25
+ return { ...state, progress: action.payload };
26
+ case 'RESET_STATE':
27
+ return { ...initialState };
28
+ default:
29
+ return state;
30
+ }
31
+ }
32
+
33
+ export default reducer;
@@ -0,0 +1,53 @@
1
+ import { Object3D } from 'three';
2
+
3
+ export enum ModelFileTypes {
4
+ gltf = 'gltf',
5
+ glb = 'glb',
6
+ usdz = 'usdz',
7
+ }
8
+
9
+ export type InputFileOrDirectory = (File | FileSystemDirectoryHandle)[];
10
+
11
+ export interface ReducedGltf {
12
+ images: { name: string; uri: string }[];
13
+ buffers: { bytelength: string; uri: string }[];
14
+ }
15
+
16
+ export interface ModelFile {
17
+ model: Object3D;
18
+ type: ModelFileTypes;
19
+ name: string;
20
+ }
21
+
22
+ // Updated State interface
23
+ export interface State {
24
+ file: ModelFile | null;
25
+ isFileLoading: boolean;
26
+ progress: number;
27
+ supportedFileTypes: ModelFileTypes[];
28
+ }
29
+
30
+ // Updated Action types
31
+ export type Action =
32
+ | { type: 'SET_FILE'; payload: ModelFile }
33
+ | { type: 'SET_FILE_LOADING'; payload: boolean }
34
+ | { type: 'SET_PROGRESS'; payload: number }
35
+ | { type: 'RESET_STATE' };
36
+
37
+ // Updated Event types
38
+ export type EventTypes =
39
+ | 'MULTIPLE_3D_MODELS'
40
+ | 'UNSUPPORTED_FILE_TYPE'
41
+ | 'UPLOAD_PROGRESS'
42
+ | 'UPLOAD_COMPLETE';
43
+
44
+ // Updated event data types
45
+ export type EventData = {
46
+ MULTIPLE_3D_MODELS: File[];
47
+ UNSUPPORTED_FILE_TYPE: File[];
48
+ UPLOAD_PROGRESS: number;
49
+ UPLOAD_COMPLETE: State['file'];
50
+ };
51
+
52
+ // Updated EventHandler type
53
+ export type EventHandler<T extends EventTypes> = (data: EventData[T]) => void;
@@ -0,0 +1,111 @@
1
+ import { useReducer, useCallback, useRef, useEffect } from 'react';
2
+
3
+ import { ModelFileTypes, InputFileOrDirectory } from './types';
4
+ import { useLoadBinary, useLoadGltf } from './file-type-hooks';
5
+ import { readDirectory } from './utils';
6
+
7
+ import eventSystem from './event-system';
8
+ import reducer, { initialState } from './state';
9
+
10
+ function useLoadModel() {
11
+ const uploadCompleteRef = useRef(false);
12
+ const [state, dispatch] = useReducer(reducer, initialState);
13
+
14
+ const { loadGltf } = useLoadGltf(dispatch);
15
+ const { loadBinary } = useLoadBinary(dispatch);
16
+
17
+ const getFileOfType = useCallback(
18
+ (files: File[], fileType: ModelFileTypes) =>
19
+ files.find((file) => file.name.endsWith('.' + fileType)),
20
+ [],
21
+ );
22
+
23
+ const updateProgress = useCallback((progress: number) => {
24
+ dispatch({ type: 'SET_PROGRESS', payload: progress });
25
+ eventSystem.emit('UPLOAD_PROGRESS', progress);
26
+ }, []);
27
+
28
+ const processFiles = useCallback(
29
+ (files: File[]) => {
30
+ if (files.length === 0) return;
31
+
32
+ dispatch({ type: 'SET_FILE_LOADING', payload: true });
33
+ updateProgress(0);
34
+ uploadCompleteRef.current = false;
35
+
36
+ const gltfFile = getFileOfType(files, ModelFileTypes.gltf);
37
+ const glbFile = getFileOfType(files, ModelFileTypes.glb);
38
+ const usdzFile = getFileOfType(files, ModelFileTypes.usdz);
39
+
40
+ const supportedFiles = [gltfFile, glbFile, usdzFile].filter(
41
+ Boolean,
42
+ ) as File[];
43
+
44
+ if (supportedFiles.length > 1) {
45
+ eventSystem.emit('MULTIPLE_3D_MODELS', supportedFiles);
46
+ return;
47
+ }
48
+
49
+ const otherFiles = files.filter(
50
+ (file) => file !== gltfFile && file !== glbFile && file !== usdzFile,
51
+ );
52
+
53
+ const updateFileProgress = (progress: number) => {
54
+ updateProgress(progress);
55
+
56
+ if (progress === 100) {
57
+ uploadCompleteRef.current = true;
58
+ }
59
+ };
60
+
61
+ if (gltfFile) {
62
+ loadGltf(gltfFile, otherFiles, updateFileProgress);
63
+ } else if (glbFile) {
64
+ loadBinary(glbFile, ModelFileTypes.glb, () => updateFileProgress(100));
65
+ } else if (usdzFile) {
66
+ loadBinary(usdzFile, ModelFileTypes.usdz, () =>
67
+ updateFileProgress(100),
68
+ );
69
+ } else {
70
+ eventSystem.emit('UNSUPPORTED_FILE_TYPE', files);
71
+ dispatch({ type: 'SET_FILE_LOADING', payload: false });
72
+ return;
73
+ }
74
+ },
75
+ [updateProgress, getFileOfType, loadGltf, loadBinary],
76
+ );
77
+
78
+ const handleFileUpload = useCallback(
79
+ async (filesOrDirectories: InputFileOrDirectory) => {
80
+ const allFiles: File[] = [];
81
+
82
+ for (const item of filesOrDirectories) {
83
+ if (item instanceof File) {
84
+ allFiles.push(item);
85
+ } else if ('kind' in item && item.kind === 'directory') {
86
+ const directoryFiles = await readDirectory(item);
87
+ allFiles.push(...directoryFiles);
88
+ }
89
+ }
90
+
91
+ processFiles(allFiles);
92
+ },
93
+ [processFiles],
94
+ );
95
+
96
+ useEffect(() => {
97
+ if (uploadCompleteRef.current && state.file) {
98
+ eventSystem.emit('UPLOAD_COMPLETE', state.file);
99
+ uploadCompleteRef.current = false;
100
+ }
101
+ }, [state.file]);
102
+
103
+ return {
104
+ ...state,
105
+ on: eventSystem.on,
106
+ off: eventSystem.off,
107
+ handleFileUpload,
108
+ };
109
+ }
110
+
111
+ export default useLoadModel;
@@ -0,0 +1,20 @@
1
+ // Helper function to convert ArrayBuffer to base64
2
+ async function arrayBufferToBase64(arrayBuffer: ArrayBuffer) {
3
+ // Create a Blob from the ArrayBuffer
4
+ const blob = new Blob([arrayBuffer]);
5
+
6
+ // Use the FileReader to convert the Blob to a Base64 string
7
+ const reader = new FileReader();
8
+ return new Promise((resolve, reject) => {
9
+ reader.onloadend = () => {
10
+ if (!reader?.result) return;
11
+ // Extract the Base64 string from the data URL
12
+ const base64String = (reader?.result as string).split(',')[1];
13
+ resolve(base64String);
14
+ };
15
+ reader.onerror = reject;
16
+ reader.readAsDataURL(blob);
17
+ });
18
+ }
19
+
20
+ export default arrayBufferToBase64;
@@ -0,0 +1,2 @@
1
+ export { default as arrayBufferToBase64 } from './array-buffer-to-base64';
2
+ export { default as readDirectory } from './read-directory';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Recursively reads a directory
3
+ *
4
+ * @param directoryHandle - The directory handle to read
5
+ * @returns - An array of file objects
6
+ */
7
+ async function readDirectory(
8
+ directoryHandle: FileSystemDirectoryHandle,
9
+ ): Promise<File[]> {
10
+ const files: File[] = [];
11
+
12
+ async function* getFilesRecursively(
13
+ entry: FileSystemDirectoryHandle,
14
+ ): AsyncGenerator<File> {
15
+ for await (const [, handle] of entry) {
16
+ if (handle.kind === 'file') {
17
+ yield await (handle as FileSystemFileHandle).getFile();
18
+ } else if (handle.kind === 'directory') {
19
+ yield* getFilesRecursively(handle as FileSystemDirectoryHandle);
20
+ }
21
+ }
22
+ }
23
+
24
+ for await (const file of getFilesRecursively(directoryHandle)) {
25
+ files.push(file);
26
+ }
27
+
28
+ return files;
29
+ }
30
+
31
+ export default readDirectory;
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react-jsx",
4
+ "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"],
5
+ "allowJs": false,
6
+ "esModuleInterop": false,
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true,
9
+ "isolatedModules": true,
10
+ "noEmit": true,
11
+ "types": ["vite/client"]
12
+ },
13
+ "files": [],
14
+ "include": [],
15
+ "references": [
16
+ {
17
+ "path": "./tsconfig.lib.json"
18
+ }
19
+ ],
20
+ "extends": "../../tsconfig.base.json"
21
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "isolatedModules": true,
6
+ "declaration": true,
7
+ "types": [
8
+ "node",
9
+ "@nx/react/typings/cssmodule.d.ts",
10
+ "@nx/react/typings/image.d.ts",
11
+ "vite/client"
12
+ ]
13
+ },
14
+ "exclude": [
15
+ "**/*.spec.ts",
16
+ "**/*.test.ts",
17
+ "**/*.spec.tsx",
18
+ "**/*.test.tsx",
19
+ "**/*.spec.js",
20
+ "**/*.test.js",
21
+ "**/*.spec.jsx",
22
+ "**/*.test.jsx"
23
+ ],
24
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
25
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,59 @@
1
+ /// <reference types='vitest' />
2
+ import { defineConfig } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+ import dts from 'vite-plugin-dts';
5
+ import * as path from 'path';
6
+ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
7
+
8
+ export default defineConfig({
9
+ root: __dirname,
10
+ cacheDir: '../../node_modules/.vite/packages/@vctrl/hooks',
11
+
12
+ plugins: [
13
+ react(),
14
+ nxViteTsPaths(),
15
+ dts({
16
+ entryRoot: 'src',
17
+ tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
18
+ }),
19
+ ],
20
+
21
+ // Uncomment this if you are using workers.
22
+ // worker: {
23
+ // plugins: [ nxViteTsPaths() ],
24
+ // },
25
+
26
+ // Configuration for building your library.
27
+ // See: https://vitejs.dev/guide/build.html#library-mode
28
+ build: {
29
+ outDir: '../../dist/packages/@vctrl/hooks',
30
+ emptyOutDir: true,
31
+ reportCompressedSize: true,
32
+ commonjsOptions: {
33
+ transformMixedEsModules: true,
34
+ },
35
+ lib: {
36
+ entry: {
37
+ index: path.resolve(__dirname, 'src/index.ts'),
38
+ 'use-load-model': path.resolve(
39
+ __dirname,
40
+ 'src/use-load-model/index.ts',
41
+ ),
42
+ },
43
+ name: '@vctrl/hooks',
44
+ formats: ['es', 'cjs'],
45
+ fileName: (format, entry) => `${entry}.${format}.js`,
46
+ },
47
+
48
+ rollupOptions: {
49
+ // External packages that should not be bundled into your library.
50
+ external: ['react', 'react-dom', 'react/jsx-runtime'],
51
+ output: {
52
+ globals: {
53
+ react: 'React',
54
+ 'react-dom': 'ReactDOM',
55
+ },
56
+ },
57
+ },
58
+ },
59
+ });