elastic / eui

Elastic UI Framework πŸ™Œ
https://eui.elastic.co/
Other
6.1k stars 840 forks source link

Vite/Rollup/ESBuild cannot process the dynamic imports in `EuiIcon` #5463

Open balthild opened 2 years ago

balthild commented 2 years ago

https://github.com/elastic/eui/blob/58b9ca3/src/components/icon/icon.tsx#L627-L633

Here the module paths is constructed by string concatation to satisfy webpack. But vite/rollup has an opposite limitation that module paths must be constructed with template strings, otherwise there'll be a such error:

Edit: seems that I misread the rollup document, but the limitation causes this problem is the module paths do not contain a file extension. It has nothing to do with template strings.

3:12:25 AM [vite] warning: 
/var/www/html/node_modules/.vite/@elastic_eui.js
47876|          return;
47877|        }
47878|        import(
   |               ^
47879|          /* webpackChunkName: "icon.[request]" */
47880|          // It's important that we don't use a template string here, it
The above dynamic import cannot be analyzed by vite.
See https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.

This results in many 404 errors in the application if it uses icons.

balthild commented 2 years ago

A workaround, using patch-package:

Click to expand `./patches/@elastic+eui+43.0.0.patch` ```patch diff --git a/node_modules/@elastic/eui/es/components/icon/icon.js b/node_modules/@elastic/eui/es/components/icon/icon.js index d8680f1..1476715 100644 --- a/node_modules/@elastic/eui/es/components/icon/icon.js +++ b/node_modules/@elastic/eui/es/components/icon/icon.js @@ -44,6 +44,7 @@ import { enqueueStateChange } from '../../services/react'; import { htmlIdGenerator } from '../../services'; import { colorToClassMap, isNamedColor } from './named_colors'; import { jsx as ___EmotionJSX } from "@emotion/react"; +import { typeToModuleMap } from './icon_imports'; var typeToPathMap = { accessibility: 'accessibility', addDataApp: 'app_add_data', @@ -557,12 +558,7 @@ export var EuiIcon = /*#__PURE__*/function (_PureComponent) { return; } - import( - /* webpackChunkName: "icon.[request]" */ - // It's important that we don't use a template string here, it - // stops webpack from building a dynamic require context. - // eslint-disable-next-line prefer-template - './assets/' + typeToPathMap[iconType]).then(function (_ref) { + typeToModuleMap[iconType]().then(function (_ref) { var icon = _ref.icon; iconComponentCache[iconType] = icon; enqueueStateChange(function () { diff --git a/node_modules/@elastic/eui/es/components/icon/icon_imports.js b/node_modules/@elastic/eui/es/components/icon/icon_imports.js new file mode 100644 index 0000000..bea416e --- /dev/null +++ b/node_modules/@elastic/eui/es/components/icon/icon_imports.js @@ -0,0 +1,436 @@ +export var typeToModuleMap = { + accessibility: () => import('./assets/accessibility.js'), + addDataApp: () => import('./assets/app_add_data.js'), + advancedSettingsApp: () => import('./assets/app_advanced_settings.js'), + agentApp: () => import('./assets/app_fleet.js'), + aggregate: () => import('./assets/aggregate.js'), + alert: () => import('./assets/alert.js'), + analyzeEvent: () => import('./assets/analyzeEvent.js'), + annotation: () => import('./assets/annotation.js'), + apmApp: () => import('./assets/app_apm.js'), + apmTrace: () => import('./assets/apm_trace.js'), + appSearchApp: () => import('./assets/app_app_search.js'), + apps: () => import('./assets/apps.js'), + arrowDown: () => import('./assets/arrow_down.js'), + arrowLeft: () => import('./assets/arrow_left.js'), + arrowRight: () => import('./assets/arrow_right.js'), + arrowUp: () => import('./assets/arrow_up.js'), + arrowStart: () => import('./assets/arrowStart.js'), + arrowEnd: () => import('./assets/arrowEnd.js'), + asterisk: () => import('./assets/asterisk.js'), + auditbeatApp: () => import('./assets/app_auditbeat.js'), + beaker: () => import('./assets/beaker.js'), + bell: () => import('./assets/bell.js'), + bellSlash: () => import('./assets/bellSlash.js'), + bolt: () => import('./assets/bolt.js'), + boxesHorizontal: () => import('./assets/boxes_horizontal.js'), + boxesVertical: () => import('./assets/boxes_vertical.js'), + branch: () => import('./assets/branch.js'), + broom: () => import('./assets/broom.js'), + brush: () => import('./assets/brush.js'), + bug: () => import('./assets/bug.js'), + bullseye: () => import('./assets/bullseye.js'), + calendar: () => import('./assets/calendar.js'), + canvasApp: () => import('./assets/app_canvas.js'), + check: () => import('./assets/check.js'), + checkInCircleFilled: () => import('./assets/checkInCircleFilled.js'), + cheer: () => import('./assets/cheer.js'), + classificationJob: () => import('./assets/ml_classification_job.js'), + clock: () => import('./assets/clock.js'), + cloudDrizzle: () => import('./assets/cloudDrizzle.js'), + cloudStormy: () => import('./assets/cloudStormy.js'), + cloudSunny: () => import('./assets/cloudSunny.js'), + codeApp: () => import('./assets/app_code.js'), + color: () => import('./assets/color.js'), + compute: () => import('./assets/compute.js'), + console: () => import('./assets/console.js'), + consoleApp: () => import('./assets/app_console.js'), + continuityAbove: () => import('./assets/continuityAbove.js'), + continuityAboveBelow: () => import('./assets/continuityAboveBelow.js'), + continuityBelow: () => import('./assets/continuityBelow.js'), + continuityWithin: () => import('./assets/continuityWithin.js'), + controlsHorizontal: () => import('./assets/controls_horizontal.js'), + controlsVertical: () => import('./assets/controls_vertical.js'), + copy: () => import('./assets/copy.js'), + copyClipboard: () => import('./assets/copy_clipboard.js'), + createAdvancedJob: () => import('./assets/ml_create_advanced_job.js'), + createMultiMetricJob: () => import('./assets/ml_create_multi_metric_job.js'), + createPopulationJob: () => import('./assets/ml_create_population_job.js'), + createSingleMetricJob: () => import('./assets/ml_create_single_metric_job.js'), + cross: () => import('./assets/cross.js'), + crossClusterReplicationApp: () => import('./assets/app_cross_cluster_replication.js'), + crossInACircleFilled: () => import('./assets/crossInACircleFilled.js'), + crosshairs: () => import('./assets/crosshairs.js'), + currency: () => import('./assets/currency.js'), + cut: () => import('./assets/cut.js'), + dashboardApp: () => import('./assets/app_dashboard.js'), + dataVisualizer: () => import('./assets/ml_data_visualizer.js'), + database: () => import('./assets/database.js'), + devToolsApp: () => import('./assets/app_devtools.js'), + discoverApp: () => import('./assets/app_discover.js'), + document: () => import('./assets/document.js'), + documentEdit: () => import('./assets/documentEdit.js'), + documentation: () => import('./assets/documentation.js'), + documents: () => import('./assets/documents.js'), + dot: () => import('./assets/dot.js'), + doubleArrowLeft: () => import('./assets/doubleArrowLeft.js'), + doubleArrowRight: () => import('./assets/doubleArrowRight.js'), + download: () => import('./assets/download.js'), + editorAlignCenter: () => import('./assets/editor_align_center.js'), + editorAlignLeft: () => import('./assets/editor_align_left.js'), + editorAlignRight: () => import('./assets/editor_align_right.js'), + editorBold: () => import('./assets/editor_bold.js'), + editorCodeBlock: () => import('./assets/editor_code_block.js'), + editorComment: () => import('./assets/editor_comment.js'), + editorDistributeHorizontal: () => import('./assets/editorDistributeHorizontal.js'), + editorDistributeVertical: () => import('./assets/editorDistributeVertical.js'), + editorHeading: () => import('./assets/editor_heading.js'), + editorItalic: () => import('./assets/editor_italic.js'), + editorItemAlignBottom: () => import('./assets/editorItemAlignBottom.js'), + editorItemAlignCenter: () => import('./assets/editorItemAlignCenter.js'), + editorItemAlignLeft: () => import('./assets/editorItemAlignLeft.js'), + editorItemAlignMiddle: () => import('./assets/editorItemAlignMiddle.js'), + editorItemAlignRight: () => import('./assets/editorItemAlignRight.js'), + editorItemAlignTop: () => import('./assets/editorItemAlignTop.js'), + editorLink: () => import('./assets/editor_link.js'), + editorOrderedList: () => import('./assets/editor_ordered_list.js'), + editorPositionBottomLeft: () => import('./assets/editorPositionBottomLeft.js'), + editorPositionBottomRight: () => import('./assets/editorPositionBottomRight.js'), + editorPositionTopLeft: () => import('./assets/editorPositionTopLeft.js'), + editorPositionTopRight: () => import('./assets/editorPositionTopRight.js'), + editorRedo: () => import('./assets/editor_redo.js'), + editorStrike: () => import('./assets/editor_strike.js'), + editorTable: () => import('./assets/editor_table.js'), + editorUnderline: () => import('./assets/editor_underline.js'), + editorUndo: () => import('./assets/editor_undo.js'), + editorUnorderedList: () => import('./assets/editor_unordered_list.js'), + email: () => import('./assets/email.js'), + empty: () => import('./assets/empty.js'), + emsApp: () => import('./assets/app_ems.js'), + eql: () => import('./assets/eql.js'), + eraser: () => import('./assets/eraser.js'), + exit: () => import('./assets/exit.js'), + expand: () => import('./assets/expand.js'), + expandMini: () => import('./assets/expandMini.js'), + exportAction: () => import('./assets/export.js'), + eye: () => import('./assets/eye.js'), + eyeClosed: () => import('./assets/eye_closed.js'), + faceHappy: () => import('./assets/face_happy.js'), + faceNeutral: () => import('./assets/face_neutral.js'), + faceSad: () => import('./assets/face_sad.js'), + filebeatApp: () => import('./assets/app_filebeat.js'), + filter: () => import('./assets/filter.js'), + flag: () => import('./assets/flag.js'), + fleetApp: () => import('./assets/app_agent.js'), + fold: () => import('./assets/fold.js'), + folderCheck: () => import('./assets/folder_check.js'), + folderClosed: () => import('./assets/folder_closed.js'), + folderExclamation: () => import('./assets/folder_exclamation.js'), + folderOpen: () => import('./assets/folder_open.js'), + frameNext: () => import('./assets/frameNext.js'), + framePrevious: () => import('./assets/framePrevious.js'), + fullScreen: () => import('./assets/full_screen.js'), + fullScreenExit: () => import('./assets/fullScreenExit.js'), + function: () => import('./assets/function.js'), + gear: () => import('./assets/gear.js'), + gisApp: () => import('./assets/app_gis.js'), + glasses: () => import('./assets/glasses.js'), + globe: () => import('./assets/globe.js'), + grab: () => import('./assets/grab.js'), + grabHorizontal: () => import('./assets/grab_horizontal.js'), + graphApp: () => import('./assets/app_graph.js'), + grid: () => import('./assets/grid.js'), + grokApp: () => import('./assets/app_grok.js'), + heart: () => import('./assets/heart.js'), + heartbeatApp: () => import('./assets/app_heartbeat.js'), + heatmap: () => import('./assets/heatmap.js'), + help: () => import('./assets/help.js'), + home: () => import('./assets/home.js'), + iInCircle: () => import('./assets/iInCircle.js'), + image: () => import('./assets/image.js'), + importAction: () => import('./assets/import.js'), + indexClose: () => import('./assets/index_close.js'), + indexEdit: () => import('./assets/index_edit.js'), + indexFlush: () => import('./assets/index_flush.js'), + indexManagementApp: () => import('./assets/app_index_management.js'), + indexMapping: () => import('./assets/index_mapping.js'), + indexOpen: () => import('./assets/index_open.js'), + indexPatternApp: () => import('./assets/app_index_pattern.js'), + indexRollupApp: () => import('./assets/app_index_rollup.js'), + indexRuntime: () => import('./assets/index_runtime.js'), + indexSettings: () => import('./assets/index_settings.js'), + inputOutput: () => import('./assets/inputOutput.js'), + inspect: () => import('./assets/inspect.js'), + invert: () => import('./assets/invert.js'), + ip: () => import('./assets/ip.js'), + keyboardShortcut: () => import('./assets/keyboard_shortcut.js'), + kqlField: () => import('./assets/kql_field.js'), + kqlFunction: () => import('./assets/kql_function.js'), + kqlOperand: () => import('./assets/kql_operand.js'), + kqlSelector: () => import('./assets/kql_selector.js'), + kqlValue: () => import('./assets/kql_value.js'), + layers: () => import('./assets/layers.js'), + lensApp: () => import('./assets/app_lens.js'), + link: () => import('./assets/link.js'), + list: () => import('./assets/list.js'), + listAdd: () => import('./assets/list_add.js'), + lock: () => import('./assets/lock.js'), + lockOpen: () => import('./assets/lockOpen.js'), + logoAWS: () => import('./assets/logo_aws.js'), + logoAWSMono: () => import('./assets/logo_aws_mono.js'), + logoAerospike: () => import('./assets/logo_aerospike.js'), + logoApache: () => import('./assets/logo_apache.js'), + logoAppSearch: () => import('./assets/logo_app_search.js'), + logoAzure: () => import('./assets/logo_azure.js'), + logoAzureMono: () => import('./assets/logo_azure_mono.js'), + logoBeats: () => import('./assets/logo_beats.js'), + logoBusinessAnalytics: () => import('./assets/logo_business_analytics.js'), + logoCeph: () => import('./assets/logo_ceph.js'), + logoCloud: () => import('./assets/logo_cloud.js'), + logoCloudEnterprise: () => import('./assets/logo_cloud_ece.js'), + logoCode: () => import('./assets/logo_code.js'), + logoCodesandbox: () => import('./assets/logo_codesandbox.js'), + logoCouchbase: () => import('./assets/logo_couchbase.js'), + logoDocker: () => import('./assets/logo_docker.js'), + logoDropwizard: () => import('./assets/logo_dropwizard.js'), + logoElastic: () => import('./assets/logo_elastic.js'), + logoElasticStack: () => import('./assets/logo_elastic_stack.js'), + logoElasticsearch: () => import('./assets/logo_elasticsearch.js'), + logoEnterpriseSearch: () => import('./assets/logo_enterprise_search.js'), + logoEtcd: () => import('./assets/logo_etcd.js'), + logoGCP: () => import('./assets/logo_gcp.js'), + logoGCPMono: () => import('./assets/logo_gcp_mono.js'), + logoGithub: () => import('./assets/logo_github.js'), + logoGmail: () => import('./assets/logo_gmail.js'), + logoGolang: () => import('./assets/logo_golang.js'), + logoGoogleG: () => import('./assets/logo_google_g.js'), + logoHAproxy: () => import('./assets/logo_haproxy.js'), + logoIBM: () => import('./assets/logo_ibm.js'), + logoIBMMono: () => import('./assets/logo_ibm_mono.js'), + logoKafka: () => import('./assets/logo_kafka.js'), + logoKibana: () => import('./assets/logo_kibana.js'), + logoKubernetes: () => import('./assets/logo_kubernetes.js'), + logoLogging: () => import('./assets/logo_logging.js'), + logoLogstash: () => import('./assets/logo_logstash.js'), + logoMaps: () => import('./assets/logo_maps.js'), + logoMemcached: () => import('./assets/logo_memcached.js'), + logoMetrics: () => import('./assets/logo_metrics.js'), + logoMongodb: () => import('./assets/logo_mongodb.js'), + logoMySQL: () => import('./assets/logo_mysql.js'), + logoNginx: () => import('./assets/logo_nginx.js'), + logoObservability: () => import('./assets/logo_observability.js'), + logoOsquery: () => import('./assets/logo_osquery.js'), + logoPhp: () => import('./assets/logo_php.js'), + logoPostgres: () => import('./assets/logo_postgres.js'), + logoPrometheus: () => import('./assets/logo_prometheus.js'), + logoRabbitmq: () => import('./assets/logo_rabbitmq.js'), + logoRedis: () => import('./assets/logo_redis.js'), + logoSecurity: () => import('./assets/logo_security.js'), + logoSiteSearch: () => import('./assets/logo_site_search.js'), + logoSketch: () => import('./assets/logo_sketch.js'), + logoSlack: () => import('./assets/logo_slack.js'), + logoUptime: () => import('./assets/logo_uptime.js'), + logoWebhook: () => import('./assets/logo_webhook.js'), + logoWindows: () => import('./assets/logo_windows.js'), + logoWorkplaceSearch: () => import('./assets/logo_workplace_search.js'), + logsApp: () => import('./assets/app_logs.js'), + logstashFilter: () => import('./assets/logstash_filter.js'), + logstashIf: () => import('./assets/logstash_if.js'), + logstashInput: () => import('./assets/logstash_input.js'), + logstashOutput: () => import('./assets/logstash_output.js'), + logstashQueue: () => import('./assets/logstash_queue.js'), + machineLearningApp: () => import('./assets/app_ml.js'), + magnet: () => import('./assets/magnet.js'), + magnifyWithMinus: () => import('./assets/magnifyWithMinus.js'), + magnifyWithPlus: () => import('./assets/magnifyWithPlus.js'), + managementApp: () => import('./assets/app_management.js'), + mapMarker: () => import('./assets/map_marker.js'), + memory: () => import('./assets/memory.js'), + menu: () => import('./assets/menu.js'), + menuDown: () => import('./assets/menuDown.js'), + menuLeft: () => import('./assets/menuLeft.js'), + menuRight: () => import('./assets/menuRight.js'), + menuUp: () => import('./assets/menuUp.js'), + merge: () => import('./assets/merge.js'), + metricbeatApp: () => import('./assets/app_metricbeat.js'), + metricsApp: () => import('./assets/app_metrics.js'), + minimize: () => import('./assets/minimize.js'), + minus: () => import('./assets/minus.js'), + minusInCircle: () => import('./assets/minus_in_circle.js'), + minusInCircleFilled: () => import('./assets/minus_in_circle_filled.js'), + mobile: () => import('./assets/mobile.js'), + monitoringApp: () => import('./assets/app_monitoring.js'), + moon: () => import('./assets/moon.js'), + nested: () => import('./assets/nested.js'), + node: () => import('./assets/node.js'), + notebookApp: () => import('./assets/app_notebook.js'), + number: () => import('./assets/number.js'), + offline: () => import('./assets/offline.js'), + online: () => import('./assets/online.js'), + outlierDetectionJob: () => import('./assets/ml_outlier_detection_job.js'), + package: () => import('./assets/package.js'), + packetbeatApp: () => import('./assets/app_packetbeat.js'), + pageSelect: () => import('./assets/pageSelect.js'), + pagesSelect: () => import('./assets/pagesSelect.js'), + paperClip: () => import('./assets/paper_clip.js'), + partial: () => import('./assets/partial.js'), + pause: () => import('./assets/pause.js'), + payment: () => import('./assets/payment.js'), + pencil: () => import('./assets/pencil.js'), + percent: () => import('./assets/percent.js'), + pin: () => import('./assets/pin.js'), + pinFilled: () => import('./assets/pin_filled.js'), + pipelineApp: () => import('./assets/app_pipeline.js'), + play: () => import('./assets/play.js'), + playFilled: () => import('./assets/playFilled.js'), + plus: () => import('./assets/plus.js'), + plusInCircle: () => import('./assets/plus_in_circle.js'), + plusInCircleFilled: () => import('./assets/plus_in_circle_filled.js'), + popout: () => import('./assets/popout.js'), + push: () => import('./assets/push.js'), + questionInCircle: () => import('./assets/question_in_circle.js'), + quote: () => import('./assets/quote.js'), + recentlyViewedApp: () => import('./assets/app_recently_viewed.js'), + refresh: () => import('./assets/refresh.js'), + regressionJob: () => import('./assets/ml_regression_job.js'), + reporter: () => import('./assets/reporter.js'), + reportingApp: () => import('./assets/app_reporting.js'), + returnKey: () => import('./assets/return_key.js'), + save: () => import('./assets/save.js'), + savedObjectsApp: () => import('./assets/app_saved_objects.js'), + scale: () => import('./assets/scale.js'), + search: () => import('./assets/search.js'), + searchProfilerApp: () => import('./assets/app_search_profiler.js'), + securityAnalyticsApp: () => import('./assets/app_security_analytics.js'), + securityApp: () => import('./assets/app_security.js'), + securitySignal: () => import('./assets/securitySignal.js'), + securitySignalDetected: () => import('./assets/securitySignalDetected.js'), + securitySignalResolved: () => import('./assets/securitySignalResolved.js'), + shard: () => import('./assets/shard.js'), + share: () => import('./assets/share.js'), + snowflake: () => import('./assets/snowflake.js'), + sortDown: () => import('./assets/sort_down.js'), + sortLeft: () => import('./assets/sortLeft.js'), + sortRight: () => import('./assets/sortRight.js'), + sortUp: () => import('./assets/sort_up.js'), + sortable: () => import('./assets/sortable.js'), + spacesApp: () => import('./assets/app_spaces.js'), + sqlApp: () => import('./assets/app_sql.js'), + starEmpty: () => import('./assets/star_empty.js'), + starEmptySpace: () => import('./assets/star_empty_space.js'), + starFilled: () => import('./assets/star_filled.js'), + starFilledSpace: () => import('./assets/star_filled_space.js'), + starMinusEmpty: () => import('./assets/star_minus_empty.js'), + starMinusFilled: () => import('./assets/star_minus_filled.js'), + starPlusEmpty: () => import('./assets/starPlusEmpty.js'), + starPlusFilled: () => import('./assets/starPlusFilled.js'), + stats: () => import('./assets/stats.js'), + stop: () => import('./assets/stop.js'), + stopFilled: () => import('./assets/stop_filled.js'), + stopSlash: () => import('./assets/stop_slash.js'), + storage: () => import('./assets/storage.js'), + string: () => import('./assets/string.js'), + submodule: () => import('./assets/submodule.js'), + swatchInput: () => import('./assets/swatch_input.js'), + // Undocumented on purpose. Has an extra stroke for EuiColorPicker + symlink: () => import('./assets/symlink.js'), + tableDensityCompact: () => import('./assets/table_density_compact.js'), + tableDensityExpanded: () => import('./assets/table_density_expanded.js'), + tableDensityNormal: () => import('./assets/table_density_normal.js'), + tableOfContents: () => import('./assets/tableOfContents.js'), + tag: () => import('./assets/tag.js'), + tear: () => import('./assets/tear.js'), + temperature: () => import('./assets/temperature.js'), + timeline: () => import('./assets/timeline.js'), + timelionApp: () => import('./assets/app_timelion.js'), + timeRefresh: () => import('./assets/timeRefresh.js'), + timeslider: () => import('./assets/timeslider.js'), + training: () => import('./assets/training.js'), + trash: () => import('./assets/trash.js'), + unfold: () => import('./assets/unfold.js'), + unlink: () => import('./assets/unlink.js'), + upgradeAssistantApp: () => import('./assets/app_upgrade_assistant.js'), + uptimeApp: () => import('./assets/app_uptime.js'), + user: () => import('./assets/user.js'), + users: () => import('./assets/users.js'), + usersRolesApp: () => import('./assets/app_users_roles.js'), + vector: () => import('./assets/vector.js'), + videoPlayer: () => import('./assets/videoPlayer.js'), + visArea: () => import('./assets/vis_area.js'), + visAreaStacked: () => import('./assets/vis_area_stacked.js'), + visBarHorizontal: () => import('./assets/vis_bar_horizontal.js'), + visBarHorizontalStacked: () => import('./assets/vis_bar_horizontal_stacked.js'), + visBarVertical: () => import('./assets/vis_bar_vertical.js'), + visBarVerticalStacked: () => import('./assets/vis_bar_vertical_stacked.js'), + visGauge: () => import('./assets/vis_gauge.js'), + visGoal: () => import('./assets/vis_goal.js'), + visLine: () => import('./assets/vis_line.js'), + visMapCoordinate: () => import('./assets/vis_map_coordinate.js'), + visMapRegion: () => import('./assets/vis_map_region.js'), + visMetric: () => import('./assets/vis_metric.js'), + visPie: () => import('./assets/vis_pie.js'), + visTable: () => import('./assets/vis_table.js'), + visTagCloud: () => import('./assets/vis_tag_cloud.js'), + visText: () => import('./assets/vis_text.js'), + visTimelion: () => import('./assets/vis_timelion.js'), + visVega: () => import('./assets/vis_vega.js'), + visVisualBuilder: () => import('./assets/vis_visual_builder.js'), + visualizeApp: () => import('./assets/app_visualize.js'), + watchesApp: () => import('./assets/app_watches.js'), + wordWrap: () => import('./assets/wordWrap.js'), + wordWrapDisabled: () => import('./assets/wordWrapDisabled.js'), + workplaceSearchApp: () => import('./assets/app_workplace_search.js'), + wrench: () => import('./assets/wrench.js'), + // Token Icon Imports + tokenClass: () => import('./assets/tokenClass.js'), + tokenProperty: () => import('./assets/tokenProperty.js'), + tokenEnum: () => import('./assets/tokenEnum.js'), + tokenVariable: () => import('./assets/tokenVariable.js'), + tokenMethod: () => import('./assets/tokenMethod.js'), + tokenAnnotation: () => import('./assets/tokenAnnotation.js'), + tokenException: () => import('./assets/tokenException.js'), + tokenInterface: () => import('./assets/tokenInterface.js'), + tokenParameter: () => import('./assets/tokenParameter.js'), + tokenField: () => import('./assets/tokenField.js'), + tokenElement: () => import('./assets/tokenElement.js'), + tokenFunction: () => import('./assets/tokenFunction.js'), + tokenBoolean: () => import('./assets/tokenBoolean.js'), + tokenString: () => import('./assets/tokenString.js'), + tokenArray: () => import('./assets/tokenArray.js'), + tokenNumber: () => import('./assets/tokenNumber.js'), + tokenConstant: () => import('./assets/tokenConstant.js'), + tokenObject: () => import('./assets/tokenObject.js'), + tokenEvent: () => import('./assets/tokenEvent.js'), + tokenKey: () => import('./assets/tokenKey.js'), + tokenNull: () => import('./assets/tokenNull.js'), + tokenStruct: () => import('./assets/tokenStruct.js'), + tokenPackage: () => import('./assets/tokenPackage.js'), + tokenOperator: () => import('./assets/tokenOperator.js'), + tokenEnumMember: () => import('./assets/tokenEnumMember.js'), + tokenRepo: () => import('./assets/tokenRepo.js'), + tokenSymbol: () => import('./assets/tokenSymbol.js'), + tokenFile: () => import('./assets/tokenFile.js'), + tokenModule: () => import('./assets/tokenModule.js'), + tokenNamespace: () => import('./assets/tokenNamespace.js'), + tokenDate: () => import('./assets/tokenDate.js'), + tokenIP: () => import('./assets/tokenIP.js'), + tokenNested: () => import('./assets/tokenNested.js'), + tokenAlias: () => import('./assets/tokenAlias.js'), + tokenShape: () => import('./assets/tokenShape.js'), + tokenGeo: () => import('./assets/tokenGeo.js'), + tokenRange: () => import('./assets/tokenRange.js'), + tokenBinary: () => import('./assets/tokenBinary.js'), + tokenJoin: () => import('./assets/tokenJoin.js'), + tokenPercolator: () => import('./assets/tokenPercolator.js'), + tokenFlattened: () => import('./assets/tokenFlattened.js'), + tokenRankFeature: () => import('./assets/tokenRankFeature.js'), + tokenRankFeatures: () => import('./assets/tokenRankFeatures.js'), + tokenKeyword: () => import('./assets/tokenKeyword.js'), + tokenTag: () => import('./assets/tokenTag.js'), + tokenCompletionSuggester: () => import('./assets/tokenCompletionSuggester.js'), + tokenDenseVector: () => import('./assets/tokenDenseVector.js'), + tokenText: () => import('./assets/tokenText.js'), + tokenTokenCount: () => import('./assets/tokenTokenCount.js'), + tokenSearchType: () => import('./assets/tokenSearchType.js'), + tokenHistogram: () => import('./assets/tokenHistogram.js') +}; ```
cee-chen commented 2 years ago

Thanks for finding this @balthild! For context, I removed the concatenated .js extension in https://github.com/elastic/eui/pull/5212 because local dev now uses Typescript / .tsx but production still compiles to .js, and Webpack was smart enough to find either the .tsx or .js version of it. I definitely didn't think of other bundlers like Rollup πŸ€¦β€β™€οΈ

I think an easy/okay solution could be detect whether we're in dev vs prod and output .tsx vs .js with that in some kind of ternary. So on line 632, something like

'./assets/' + typeToPathMap[iconType] + (process.env.NODE_ENV !== 'production' ? '.tsx' : '.js')

No idea if EUI is setting NODE_ENV however or how that would actually work in a consumer environment, so someone should definitely double check that or find a condition that works πŸ™ˆ

balthild commented 2 years ago

I'm not sure if vite could recognize a conditional string now, but I've find that I'm running into another problem that prevents us to confirm this - vite does not transpile the dynamic imports in a dependency module at all (vitejs/vite#6179). This is why the workaround I'd posted above adds a long typeToModuleMap object rather than simply adds .js file extension to the import expression. I think this issue is therefore not possible to fix before vitejs/vite#6179 is fixed.

cee-chen commented 2 years ago

Ahhh, gotcha. Another alternative for consuming EuiIcons is how SSRs handle it: https://github.com/elastic/eui/tree/main/wiki/consuming-eui#failing-icon-imports

henry-young commented 2 years ago

Vite user here. Using the appendIconComponentCache() method works well enough when I'm creating my own components. The DX falls down when adding components with many different icons (such as EuiInMemoryTable) because I have to search the source code. It would be nice to have a list of icons the component uses in the docs.

TomSoldier commented 2 years ago

Hi @henry-young, I use Vite too and have run into a similar problem. How did you get the appendIconComponentCache function to work? Could you give an example of its use in Vite?

henry-young commented 2 years ago

Hi @henry-young, I use Vite too and have run into a similar problem. How did you get the appendIconComponentCache function to work? Could you give an example of its use in Vite?

Firstly in vite.config.js I added

export default defineConfig({
  ...
  build: {
   ...
    dynamicImportVarsOptions: {
      exclude: [],
    },
  },
  ...
});

and then I just have a file named ~/src/icons.ts that contains.

import { ICON_TYPES } from '@elastic/eui';
import { ValuesType } from 'utility-types';

import { appendIconComponentCache } from '@elastic/eui/es/components/icon/icon';

import { icon as magnifyWithMinus } from '@elastic/eui/es/components/icon/assets/magnifyWithMinus';
import { icon as minus } from '@elastic/eui/es/components/icon/assets/minus';
import { icon as magnifyWithPlus } from '@elastic/eui/es/components/icon/assets/magnifyWithPlus';
import { icon as plus } from '@elastic/eui/es/components/icon/assets/plus';

type IconComponentNameType = ValuesType<typeof ICON_TYPES>;
type IconComponentCacheType = Partial<Record<IconComponentNameType, unknown>>;

const cachedIcons: IconComponentCacheType = {
  magnifyWithMinus,
  magnifyWithPlus,
  minus,
  plus,
  ...
};

appendIconComponentCache(cachedIcons);

And then a global.d.ts file containing a basic module definition for the icons (so typescript doesn't complain)

declare module '@elastic/eui/es/components/icon/*';

I hope that helps.

TomSoldier commented 2 years ago

Hi @henry-young, I use Vite too and have run into a similar problem. How did you get the appendIconComponentCache function to work? Could you give an example of its use in Vite?

Firstly in vite.config.js I added

export default defineConfig({
  ...
  build: {
   ...
    dynamicImportVarsOptions: {
      exclude: [],
    },
  },
  ...
});

and then I just have a file named ~/src/icons.ts that contains.

import { ICON_TYPES } from '@elastic/eui';
import { ValuesType } from 'utility-types';

import { appendIconComponentCache } from '@elastic/eui/es/components/icon/icon';

import { icon as magnifyWithMinus } from '@elastic/eui/es/components/icon/assets/magnifyWithMinus';
import { icon as minus } from '@elastic/eui/es/components/icon/assets/minus';
import { icon as magnifyWithPlus } from '@elastic/eui/es/components/icon/assets/magnifyWithPlus';
import { icon as plus } from '@elastic/eui/es/components/icon/assets/plus';

type IconComponentNameType = ValuesType<typeof ICON_TYPES>;
type IconComponentCacheType = Partial<Record<IconComponentNameType, unknown>>;

const cachedIcons: IconComponentCacheType = {
  magnifyWithMinus,
  magnifyWithPlus,
  minus,
  plus,
  ...
};

appendIconComponentCache(cachedIcons);

And then a global.d.ts file containing a basic module definition for the icons (so typescript doesn't complain)

declare module '@elastic/eui/es/components/icon/*';

I hope that helps.

Thank you, I understand how it works now. I missed the module declaration.

cee-chen commented 2 years ago

Thanks for posting that super detailed comment @henry-young!

It would be nice to have a list of icons the component uses in the docs.

Maybe I'm missing something, but you definitely shouldn't have to search our source code to look at a list of all our icons - they should be available for preview/search at https://elastic.github.io/eui/#/display/icons#glyphs (you can click the icon to copy the iconType). Hope that helps!

TomSoldier commented 2 years ago

Thanks for posting that super detailed comment @henry-young!

It would be nice to have a list of icons the component uses in the docs.

Maybe I'm missing something, but you definitely shouldn't have to search our source code to look at a list of all our icons - they should be available for preview/search at https://elastic.github.io/eui/#/display/icons#glyphs (you can click the icon to copy the iconType). Hope that helps!

@constancecchen , I think he thought, for example, that the API pages of table components like EuiTable doesn't have the names of the icons used by the component, so it's hard to know what icons we want to cache. The same is true for other components that use built-in icons.

cee-chen commented 2 years ago

Ah, you're totally right, I missed that context, apologies! We're not likely to update our docs to include a list of all icons each component uses as SSR consumers are still an edge case for us (and for the original issue, the file extension issue can be addressed either by Vite or EUI) - but as Henry did it's possible for consumers to grep through our source code for components looking for either EuiIcon or iconType.

badwulfy commented 2 years ago

I use Parcel bundler and I have the same issue. As I don't like to add each icon by hand, I made a patch for the latest version of Elastic UI : https://gist.github.com/badwulfy/2a59c5ab8866439ff074e05e136b653d

thompsongl commented 2 years ago

We had a brief sync about this today, and we'd be open to changing the import method. One difficulty I see with the referenced path is that we have 4 different builds (es, lib, optimize/es, and optimize/lib) and the import path would need to change for each:

accessibility: () => import('@elastic/eui/es/components/icon/assets/accessibility')

Right now each build, as well as local dev (with webpack dev server), work because of the relative './assets/' pathing in the concatenated string. We'd need to alter the import at build time to accommodate each build but keep local imports working for dev environments.

jgentes commented 2 years ago

+1 for having a simpler solution, but nice to have a workaround. I'm using Vite.

j-m commented 1 year ago

Out of curiosity, why is a dynamic import needed here? Why not just rely on tree-shaking?

For those applying the patch now, you need to remove keyboardShortcut (I've not checked for any new icons)

lightwave commented 1 year ago

and then I just have a file named ~/src/icons.ts that contains.

@henry-young What do I do with icons.ts? Do I have to import it somewhere or put it in vite.config.js? I follow your work around but icons are still not showing up.

henry-young commented 1 year ago

and then I just have a file named ~/src/icons.ts that contains.

@henry-young What do I do with icons.ts? Do I have to import it somewhere or put it in vite.config.js? I follow your work around but icons are still not showing up.

I put import "~/src/icons"; at the top of my main.tsx (the file containing ReactDOM.render()). I do this to make sure that the icon cache code is run before the app starts.

You could wrap appendIconComponentCache(cachedIcons); in a function and export it so you could execute that exactly when you want it to. I didn't have a need to do it that way, but you might if that suits your needs.

lightwave commented 1 year ago

@henry-young Thanks! That works perfectly.

unckleg commented 1 year ago

Thanks me later: https://gist.github.com/unckleg/5476ebd940d1d473387bb082e8c2929c

prcdpr commented 1 year ago

Similar to above but fixed a couple of icons (function, package and others) Also with TypeScript checking:

https://gist.github.com/prcdpr/c328461847d991b2492d20220456133e

Alecton4 commented 1 year ago

Updated icons.all.ts for TypeScript: https://gist.github.com/Alecton4/66c9eee74ad94d463523a8dfb65f6a01

leaftail1880 commented 11 months ago

Tool to dynamically generate icon list (Change file path according to your needs)

All you need beside generated file is global.d.ts somewhere with

declare module '@elastic/eui/es/components/icon/*';

And in main.tsx

import 'icons/icons'
lpkobamn commented 3 months ago

Tool to dynamically generate icon list (Change file path according to your needs)

All you need beside generated file is global.d.ts somewhere with

declare module '@elastic/eui/es/components/icon/*';

And in main.tsx

import 'icons/icons'

thanks!