diff --git a/vite.config.base.ts b/vite.config.base.ts new file mode 100644 index 000000000..6dc2aee3c --- /dev/null +++ b/vite.config.base.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite'; +import path from 'path'; + +export default defineConfig({ + resolve: { + alias: { + vue: 'vue/dist/vue.esm-bundler.js', + components: path.resolve('./app/javascript/dashboard/components'), + next: path.resolve('./app/javascript/dashboard/components-next'), + v3: path.resolve('./app/javascript/v3'), + dashboard: path.resolve('./app/javascript/dashboard'), + helpers: path.resolve('./app/javascript/shared/helpers'), + shared: path.resolve('./app/javascript/shared'), + survey: path.resolve('./app/javascript/survey'), + widget: path.resolve('./app/javascript/widget'), + assets: path.resolve('./app/javascript/dashboard/assets'), + }, + }, +}); diff --git a/vite.config.dev.ts b/vite.config.dev.ts new file mode 100644 index 000000000..19a507275 --- /dev/null +++ b/vite.config.dev.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite'; +import ruby from 'vite-plugin-ruby'; +import vue from '@vitejs/plugin-vue'; +import baseConfig from './vite.config.base'; +import { mergeConfig } from 'vite'; + +const vueOptions = { + template: { + compilerOptions: { + isCustomElement: tag => ['ninja-keys'].includes(tag), + }, + }, +}; + +const defaultConfig = defineConfig({ + plugins: [ruby(), vue(vueOptions)], + build: { + rollupOptions: { + output: { + inlineDynamicImports: false, + }, + }, + }, +}); + +export default mergeConfig(baseConfig, defaultConfig); diff --git a/vite.config.lib.ts b/vite.config.lib.ts new file mode 100644 index 000000000..2306403d0 --- /dev/null +++ b/vite.config.lib.ts @@ -0,0 +1,29 @@ +import { defineConfig } from 'vite'; +import path from 'path'; +import baseConfig from './vite.config.base'; +import { mergeConfig } from 'vite'; + +const libraryConfig = defineConfig({ + plugins: [], + build: { + rollupOptions: { + output: { + dir: 'public/packs', + entryFileNames: chunkInfo => { + if (chunkInfo.name === 'sdk') { + return 'js/sdk.js'; + } + return '[name].js'; + }, + inlineDynamicImports: true, // Disable code-splitting for SDK + }, + }, + lib: { + entry: path.resolve(__dirname, './app/javascript/entrypoints/sdk.js'), + formats: ['iife'], // IIFE format for single file + name: 'sdk', + }, + }, +}); + +export default mergeConfig(baseConfig, libraryConfig); diff --git a/vite.config.story.ts b/vite.config.story.ts new file mode 100644 index 000000000..2ea975894 --- /dev/null +++ b/vite.config.story.ts @@ -0,0 +1,41 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import baseConfig from './vite.config.base'; +import { mergeConfig } from 'vite'; + +const vueOptions = { + template: { + compilerOptions: { + isCustomElement: tag => ['ninja-keys'].includes(tag), + }, + }, +}; + +const testConfig = defineConfig({ + plugins: [vue(vueOptions)], + test: { + environment: 'jsdom', + include: ['app/**/*.{test,spec}.?(c|m)[jt]s?(x)'], + coverage: { + reporter: ['lcov', 'text'], + include: ['app/**/*.js', 'app/**/*.vue'], + exclude: [ + 'app/**/*.@(spec|stories|routes).js', + '**/specs/**/*', + '**/i18n/**/*', + ], + }, + globals: true, + outputFile: 'coverage/sonar-report.xml', + server: { + deps: { + inline: ['tinykeys', '@material/mwc-icon'], + }, + }, + setupFiles: ['fake-indexeddb/auto', 'vitest.setup.js'], + mockReset: true, + clearMocks: true, + }, +}); + +export default mergeConfig(baseConfig, testConfig); diff --git a/vite.config.test.ts b/vite.config.test.ts new file mode 100644 index 000000000..805300ee8 --- /dev/null +++ b/vite.config.test.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import baseConfig from './vite.config.base'; +import { mergeConfig } from 'vite'; + +const vueOptions = { + template: { + compilerOptions: { + isCustomElement: tag => ['ninja-keys'].includes(tag), + }, + }, +}; + +const testConfig = defineConfig({ + plugins: [vue(vueOptions)], +}); + +export default mergeConfig(baseConfig, testConfig); diff --git a/vite.config.ts b/vite.config.ts index 8af1a9538..01e83e34a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,111 +1,18 @@ /// -/** -What's going on with library mode? - -Glad you asked, here's a quick rundown: - -1. vite-plugin-ruby will automatically bring all the entrypoints like dashbord and widget as input to vite. -2. vite needs to be in library mode to build the SDK as a single file. (UMD) format and set `inlineDynamicImports` to true. -3. But when setting `inlineDynamicImports` to true, vite will not be able to handle mutliple entrypoints. - -This puts us in a deadlock, now there are two ways around this, either add another separate build pipeline to -the app using vanilla rollup or rspack or something. The second option is to remove sdk building from the main pipeline -and build it separately using Vite itself, toggled by an ENV variable. - -`BUILD_MODE=library bin/vite build` should build only the SDK and save it to `public/packs/js/sdk.js` -`bin/vite build` will build the rest of the app as usual. But exclude the SDK. - -We need to edit the `asset:precompile` rake task to include the SDK in the precompile list. -*/ -import { defineConfig } from 'vite'; -import ruby from 'vite-plugin-ruby'; -import path from 'path'; -import vue from '@vitejs/plugin-vue'; - const isLibraryMode = process.env.BUILD_MODE === 'library'; const isTestMode = process.env.TEST === 'true'; +const isStoryMode = process.env.BUILD_MODE === 'story'; -const vueOptions = { - template: { - compilerOptions: { - isCustomElement: tag => ['ninja-keys'].includes(tag), - }, - }, -}; - -let plugins = [ruby(), vue(vueOptions)]; - +let config; if (isLibraryMode) { - plugins = []; + config = import('./vite.config.lib'); } else if (isTestMode) { - plugins = [vue(vueOptions)]; + config = import('./vite.config.test'); +} else if (isStoryMode) { + config = import('./vite.config.dev'); +} else { + config = import('./vite.config.dev'); } -export default defineConfig({ - plugins: plugins, - build: { - rollupOptions: { - output: { - // [NOTE] when not in library mode, no new keys will be addedd or overwritten - // setting dir: isLibraryMode ? 'public/packs' : undefined will not work - ...(isLibraryMode - ? { - dir: 'public/packs', - entryFileNames: chunkInfo => { - if (chunkInfo.name === 'sdk') { - return 'js/sdk.js'; - } - return '[name].js'; - }, - } - : {}), - inlineDynamicImports: isLibraryMode, // Disable code-splitting for SDK - }, - }, - lib: isLibraryMode - ? { - entry: path.resolve(__dirname, './app/javascript/entrypoints/sdk.js'), - formats: ['iife'], // IIFE format for single file - name: 'sdk', - } - : undefined, - }, - resolve: { - alias: { - vue: 'vue/dist/vue.esm-bundler.js', - components: path.resolve('./app/javascript/dashboard/components'), - next: path.resolve('./app/javascript/dashboard/components-next'), - v3: path.resolve('./app/javascript/v3'), - dashboard: path.resolve('./app/javascript/dashboard'), - helpers: path.resolve('./app/javascript/shared/helpers'), - shared: path.resolve('./app/javascript/shared'), - survey: path.resolve('./app/javascript/survey'), - widget: path.resolve('./app/javascript/widget'), - assets: path.resolve('./app/javascript/dashboard/assets'), - }, - }, - test: { - environment: 'jsdom', - include: ['app/**/*.{test,spec}.?(c|m)[jt]s?(x)'], - coverage: { - reporter: ['lcov', 'text'], - include: ['app/**/*.js', 'app/**/*.vue'], - exclude: [ - 'app/**/*.@(spec|stories|routes).js', - '**/specs/**/*', - '**/i18n/**/*', - ], - }, - globals: true, - outputFile: 'coverage/sonar-report.xml', - server: { - deps: { - inline: ['tinykeys', '@material/mwc-icon'], - }, - }, - setupFiles: ['fake-indexeddb/auto', 'vitest.setup.js'], - mockReset: true, - clearMocks: true, - }, -}); +export default config;