init
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"project": "./tsconfig.json"
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0.2"
|
||||
}
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"react",
|
||||
"import",
|
||||
"@typescript-eslint",
|
||||
"unused-imports"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"impliedStrict": true,
|
||||
"modules": true,
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"jquery": false,
|
||||
"es6": true
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "warn",
|
||||
"no-unused-expressions": "warn",
|
||||
"unused-imports/no-unused-imports": "warn",
|
||||
"import/no-named-as-default": "off"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.eslintcache
|
||||
junit.xml
|
||||
node_modules
|
||||
@@ -0,0 +1 @@
|
||||
save-exact=true
|
||||
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=22",
|
||||
"npm": ">=10"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite",
|
||||
"lint": "eslint --ignore-pattern node_modules --ignore-pattern dist --ext .js --ext .jsx --ext tsx --ext ts . --quiet --cache",
|
||||
"fix": "eslint --ignore-pattern node_modules --ignore-pattern dist --ext .js --ext .jsx --ext tsx --ext ts . --quiet --fix --cache",
|
||||
"check-types": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-modules-umd": "^7.27.1",
|
||||
"@babel/preset-typescript": "^7.27.1",
|
||||
"@emotion/core": "10.0.28",
|
||||
"@eslint/js": "^9.25.1",
|
||||
"@rollup/plugin-replace": "^6.0.2",
|
||||
"@types/node": "14.0.20",
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17",
|
||||
"@types/react-intl": "3.0.0",
|
||||
"@types/react-redux": "7.1.9",
|
||||
"@types/react-router-dom": "5.1.5",
|
||||
"@types/react-transition-group": "4.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "3.6.0",
|
||||
"@typescript-eslint/parser": "3.6.0",
|
||||
"@vitejs/plugin-react": "^4.4.1",
|
||||
"bootstrap": "5.1.3",
|
||||
"core-js": "3.6.5",
|
||||
"css-loader": "7.1.2",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-plugin-import": "2.22.0",
|
||||
"eslint-plugin-react": "7.20.3",
|
||||
"eslint-plugin-react-hooks": "4.0.6",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"file-loader": "6.0.0",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"loop-plugin-sdk": "https://artifacts.wilix.dev/repository/npm-public-loop/loop-plugin-sdk/-/loop-plugin-sdk-0.1.6.tgz",
|
||||
"moment-timezone": "^0.5.48",
|
||||
"react": "17.0.2",
|
||||
"react-bootstrap": "^2.10.10",
|
||||
"react-dom": "17.0.2",
|
||||
"react-intl": "6.8.9",
|
||||
"react-redux": "8.1.3",
|
||||
"redux": "4.2.1",
|
||||
"sass": "1.86.0",
|
||||
"sass-loader": "13.0.2",
|
||||
"style-loader": "1.2.1",
|
||||
"styled-components": "6.1.16",
|
||||
"typescript": "4.9.5",
|
||||
"typescript-eslint": "^8.31.1",
|
||||
"vite": "^6.3.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.5.2",
|
||||
"vite-plugin-externals": "^0.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1",
|
||||
"redux-batched-actions": "^0.5.0"
|
||||
},
|
||||
"packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import manifest from '../manifest';
|
||||
import usePlugin from '../utils/usePlugin';
|
||||
|
||||
const RootComponent: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const plugin = usePlugin();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Add your root component content here */}
|
||||
<p>Template Plugin Root Component</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RootComponent
|
||||
@@ -0,0 +1 @@
|
||||
// Add your global styles here
|
||||
@@ -0,0 +1,14 @@
|
||||
import { getPluginAssetsPath } from '../utils/utils';
|
||||
|
||||
export const basePath = getPluginAssetsPath();
|
||||
|
||||
// Add your assets configuration here
|
||||
export type AssetsType = {
|
||||
// Define your asset types
|
||||
}
|
||||
|
||||
const assets: AssetsType = {
|
||||
// Add your assets here
|
||||
} as const
|
||||
|
||||
export default assets
|
||||
@@ -0,0 +1,5 @@
|
||||
import Svgs from './svgs.js';
|
||||
|
||||
export {
|
||||
Svgs,
|
||||
};
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
|
||||
type Props = {
|
||||
icon: string,
|
||||
className?: string,
|
||||
} & React.HTMLAttributes<HTMLElement>
|
||||
|
||||
export default function CompassIcon({icon, className, ...rest}: Props): JSX.Element {
|
||||
// All compass icon classes start with icon,
|
||||
// so not expecting that prefix in props.
|
||||
return (
|
||||
<i
|
||||
className={`CompassIcon icon-${icon} ${className}`}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { PluginRegistry } from 'loop-plugin-sdk';
|
||||
import { Store, Action } from 'redux';
|
||||
import { GlobalState } from 'loop-plugin-sdk/loop/types/store';
|
||||
import 'loop-plugin-sdk/window'
|
||||
import manifest from './manifest';
|
||||
import registerApp from './registerApp';
|
||||
|
||||
export default class Plugin {
|
||||
// @ts-ignore
|
||||
public store: Store;
|
||||
|
||||
// @ts-ignore
|
||||
public registry: PluginRegistry
|
||||
|
||||
public onStoreChanged: any;
|
||||
public uninitialize: any;
|
||||
|
||||
public async initialize(registry: PluginRegistry, store: Store<GlobalState, Action<Record<string, unknown>>>) {
|
||||
this.store = store;
|
||||
this.registry = registry;
|
||||
|
||||
await registerApp(this, registry, store)
|
||||
}
|
||||
}
|
||||
|
||||
window.registerPlugin(manifest.id, new Plugin());
|
||||
@@ -0,0 +1,49 @@
|
||||
import { PluginRegistry } from 'loop-plugin-sdk';
|
||||
import { getCurrentUserLocale } from 'loop-plugin-sdk/loop/redux/selectors/entities/i18n';
|
||||
import { Action, Store } from 'redux';
|
||||
import RootComponent from './components/RootComponent';
|
||||
import Plugin from './index';
|
||||
import manifest from './manifest';
|
||||
import reducer from './store/reducers';
|
||||
import * as React from 'react';
|
||||
import { getTranslations } from './utils/utils';
|
||||
import { Provider, useSelector } from 'react-redux';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { GlobalState } from 'loop-plugin-sdk/loop/types/store';
|
||||
|
||||
export const pluginStoreId = `plugins-${manifest.id}`;
|
||||
|
||||
export default async function Initialize(plugin: Plugin, registry: PluginRegistry, store: Store<GlobalState, Action<Record<string, unknown>>>) {
|
||||
const Providers: React.FC<React.PropsWithChildren<any>> = ({ children }) => {
|
||||
const locale = useSelector((state) => getCurrentUserLocale(state as GlobalState) || 'en');
|
||||
return (
|
||||
<IntlProvider locale={locale} key={locale} messages={getTranslations(locale)}>
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</IntlProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const regIds: string[] = [];
|
||||
|
||||
registry.registerReducer(reducer);
|
||||
registry.registerTranslations(getTranslations);
|
||||
|
||||
plugin.uninitialize = () => {
|
||||
// Add cleanup logic here
|
||||
};
|
||||
|
||||
const reinit = () => {
|
||||
if (regIds.length > 0) {
|
||||
regIds.forEach(regId => registry.unregisterComponent(regId));
|
||||
regIds.splice(0, regIds.length);
|
||||
}
|
||||
|
||||
regIds.push(registry.registerRootComponent(() => (
|
||||
<Providers>
|
||||
<RootComponent />
|
||||
</Providers>
|
||||
)));
|
||||
};
|
||||
|
||||
reinit();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { DispatchFunc } from '../types/store';
|
||||
import { ACTIONS } from './reducers';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
// Add your action creators here
|
||||
export function exampleAction(data: string) {
|
||||
return ((dispatch: DispatchFunc) => {
|
||||
dispatch({
|
||||
type: ACTIONS.EXAMPLE_ACTION,
|
||||
data: { example: data }
|
||||
});
|
||||
}) as unknown as AnyAction;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import { PluginStore } from '../types/store';
|
||||
|
||||
export type ActionType = {
|
||||
type: ACTIONS
|
||||
data: PluginActionData
|
||||
}
|
||||
|
||||
export enum ACTIONS {
|
||||
// Add your action types here
|
||||
EXAMPLE_ACTION = 'EXAMPLE_ACTION',
|
||||
}
|
||||
|
||||
export type PluginActionData = {
|
||||
// Add your action data types here
|
||||
example?: string;
|
||||
}
|
||||
|
||||
const EmptyState: PluginStore = {
|
||||
// Add your initial state here
|
||||
}
|
||||
|
||||
function pluginState(state: PluginStore = EmptyState, { type, data }: ActionType): PluginStore {
|
||||
switch (type) {
|
||||
case ACTIONS.EXAMPLE_ACTION:
|
||||
return {
|
||||
...state,
|
||||
// Handle action
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default combineReducers({
|
||||
pluginState,
|
||||
});
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import Plugin from '../index';
|
||||
|
||||
declare module "*.module.css";
|
||||
declare module "*.module.scss";
|
||||
|
||||
declare global {
|
||||
const __PLUGIN_DEV__: boolean;
|
||||
const __PLUGIN_COMPONENTS_HOST__: string | null;
|
||||
|
||||
interface Window {
|
||||
plugins: Record<string, Plugin | unknown>;
|
||||
basename: string;
|
||||
desktopAPI?: any;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { GlobalState } from 'loop-plugin-sdk/loop/types/store';
|
||||
import { ActionType } from '../store/reducers';
|
||||
|
||||
export type PluginStore = {
|
||||
// Add your store state here
|
||||
}
|
||||
|
||||
export type GlobalStatePlugin = GlobalState & {
|
||||
[name: string]: {
|
||||
pluginState: PluginStore
|
||||
}
|
||||
}
|
||||
|
||||
export type GetStateType = () => GlobalStatePlugin
|
||||
|
||||
export type DispatchFunc = (action: ActionType) => any;
|
||||
@@ -0,0 +1 @@
|
||||
// trackEvent: (event: Telemetry.Event, source: Telemetry.Source, props?: Record<string, string>) => void,
|
||||
@@ -0,0 +1,39 @@
|
||||
import Client4 from 'loop-plugin-sdk/loop/client/client4';
|
||||
import manifest from '../manifest';
|
||||
|
||||
export type StdApiResp<T = undefined> = {
|
||||
status: string
|
||||
error?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
class ApiClient {
|
||||
client = new Client4();
|
||||
|
||||
async exampleRequest(): Promise<StdApiResp<{ message: string }>> {
|
||||
try {
|
||||
// @ts-ignore
|
||||
return await this.client.doFetch<StdApiResp<{ message: string }>>(`/plugins/${manifest.id}/example`, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {status: 'error', error: error as string};
|
||||
}
|
||||
}
|
||||
|
||||
async apiPingServerStatus(): Promise<boolean> {
|
||||
try {
|
||||
const response = await this.client.ping();
|
||||
return response.status === 'OK';
|
||||
} catch (err) {
|
||||
console.error('Ошибка пинга сервера:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const apiClient = new ApiClient();
|
||||
|
||||
export default apiClient
|
||||
@@ -0,0 +1,18 @@
|
||||
import { getTheme } from 'loop-plugin-sdk/loop/redux/selectors/entities/preferences';
|
||||
import { GlobalState } from 'loop-plugin-sdk/loop/types/store';
|
||||
import React, { useEffect } from "react";
|
||||
import { useSelector } from 'react-redux';
|
||||
import { isDarkTheme } from './colorUtils';
|
||||
|
||||
const useIsDarkTheme = () => {
|
||||
const [isDark, setIsDark] = React.useState(false);
|
||||
const theme = useSelector((state: GlobalState) => getTheme(state))
|
||||
|
||||
useEffect(() => {
|
||||
setIsDark(isDarkTheme());
|
||||
}, [theme])
|
||||
|
||||
return isDark
|
||||
}
|
||||
|
||||
export default useIsDarkTheme
|
||||
@@ -0,0 +1,6 @@
|
||||
import Plugin from '../index';
|
||||
import manifest from '../manifest';
|
||||
|
||||
export default function usePlugin() {
|
||||
return window.plugins[manifest.id] as Plugin
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { WebSocketClient } from 'loop-plugin-sdk/loop/client';
|
||||
import { DispatchFunc } from 'loop-plugin-sdk/loop/redux/types/actions';
|
||||
import { GlobalState } from 'loop-plugin-sdk/loop/types/store';
|
||||
import { AnyAction } from 'redux';
|
||||
import en from '../../i18n/en.json';
|
||||
import ru from '../../i18n/ru.json';
|
||||
import Plugin from '../index';
|
||||
import manifest from '../manifest';
|
||||
import { pluginStoreId } from '../registerApp';
|
||||
import { GlobalStatePlugin } from '../types/store';
|
||||
|
||||
export function getPluginAssetsPath() {
|
||||
return `${window.basename || ''}/plugins/${manifest.id}/assets`;
|
||||
}
|
||||
|
||||
export function getPlugin(): Plugin {
|
||||
return window.plugins[manifest.id] as Plugin;
|
||||
}
|
||||
|
||||
export function isDesktopApp(): boolean {
|
||||
return window.navigator.userAgent.indexOf('Electron') !== -1;
|
||||
}
|
||||
|
||||
export function getWebappUtils() {
|
||||
let utils;
|
||||
try {
|
||||
utils = window.opener ? window.opener.WebappUtils : window.WebappUtils;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return utils;
|
||||
}
|
||||
|
||||
export type ProductApi = {
|
||||
selectRhsPost: (postId: string) => (dispatch: DispatchFunc) => AnyAction
|
||||
closeRhs: () => (dispatch: DispatchFunc) => AnyAction
|
||||
getIsRhsOpen: (state: GlobalState) => boolean
|
||||
getRhsSelectedPostId: (state: GlobalState) => string
|
||||
useWebSocketClient: () => WebSocketClient
|
||||
}
|
||||
|
||||
export function getProductApi(): ProductApi {
|
||||
let utils: any;
|
||||
try {
|
||||
// @ts-ignore
|
||||
utils = window.opener ? window.opener.ProductApi : window['ProductApi'];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return utils;
|
||||
}
|
||||
|
||||
export function getPluginStoreFromState(state: GlobalStatePlugin) {
|
||||
return state[pluginStoreId].pluginState;
|
||||
}
|
||||
|
||||
export function getTranslations(locale: string) {
|
||||
switch (locale) {
|
||||
case "en":
|
||||
return en;
|
||||
case "ru":
|
||||
return ru;
|
||||
}
|
||||
return en;
|
||||
}
|
||||
|
||||
export function getRandomInt(min: number, max: number) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
export async function waitForServer(
|
||||
pingFn: () => Promise<any>,
|
||||
interval = 2000,
|
||||
maxAttempts = 10
|
||||
): Promise<void> {
|
||||
let attempts = 0;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const check = async () => {
|
||||
attempts++;
|
||||
const ok = await pingFn();
|
||||
if (ok) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (attempts >= maxAttempts) {
|
||||
reject(new Error("Не удалось подключиться после нескольких попыток"));
|
||||
return;
|
||||
}
|
||||
setTimeout(check, interval);
|
||||
};
|
||||
check();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "es2020",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "react",
|
||||
"baseUrl": "./src",
|
||||
"typeRoots": [ "./src/types", "./node_modules/@types"],
|
||||
"types": ["vite/client"],
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"!node_modules/@types"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { resolve } from "path";
|
||||
import { defineConfig } from 'vite'
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { viteExternalsPlugin } from 'vite-plugin-externals';
|
||||
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
|
||||
import manifest from './src/manifest';
|
||||
|
||||
const isDev = ['development', 'develop'].includes(process.env.NODE_ENV);
|
||||
|
||||
console.warn('Vite building in ', isDev ? 'DEVELOPER MODE' : 'PRODUCTION MODE');
|
||||
|
||||
const optimizeDepsInclude = [
|
||||
'**/*.scss',
|
||||
];
|
||||
// В dev: подготавливаем react/react-dom/react-redux как ESM-шимы
|
||||
if (isDev) {
|
||||
optimizeDepsInclude.push('react-redux')
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
...(isDev ? [
|
||||
viteExternalsPlugin({
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
redux: 'Redux',
|
||||
'react-redux': 'ReactRedux',
|
||||
'prop-types': 'PropTypes',
|
||||
'react-bootstrap': 'ReactBootstrap',
|
||||
'react-router-dom': 'ReactRouterDom',
|
||||
}),
|
||||
] : [
|
||||
]),
|
||||
|
||||
// 2) В dev включаем плагин React (он генерит preamble + jsx runtime + fast refresh)
|
||||
...(isDev ? [react()] : []),
|
||||
|
||||
cssInjectedByJsPlugin(),
|
||||
replace({
|
||||
// Переопределяем NODE_ENV внутри бандла
|
||||
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
|
||||
preventAssignment: true,
|
||||
}),
|
||||
],
|
||||
|
||||
// Трансформация JSX через esbuild
|
||||
esbuild: {
|
||||
jsx: 'transform',
|
||||
jsxFactory: 'React.createElement',
|
||||
jsxFragment: 'React.Fragment',
|
||||
},
|
||||
|
||||
// В dev: подготавливаем react/react-dom/react-redux как ESM-шимы
|
||||
optimizeDeps: {
|
||||
include: optimizeDepsInclude,
|
||||
},
|
||||
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
modules: true,
|
||||
},
|
||||
},
|
||||
modules: {
|
||||
localsConvention: 'camelCaseOnly',
|
||||
},
|
||||
},
|
||||
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/index.tsx'),
|
||||
formats: ['umd'],
|
||||
name: manifest.id,
|
||||
cssFileName: manifest.id,
|
||||
fileName: () => 'main.js',
|
||||
},
|
||||
rollupOptions: {
|
||||
// В проде всё это выносится в глобальные переменные Mattermost
|
||||
external: [
|
||||
'react',
|
||||
'react-dom',
|
||||
'redux',
|
||||
'react-redux',
|
||||
'prop-types',
|
||||
'react-bootstrap',
|
||||
'react-router-dom',
|
||||
'core-js',
|
||||
'react-intl',
|
||||
],
|
||||
output: {
|
||||
inlineDynamicImports: true,
|
||||
manualChunks: undefined,
|
||||
globals: {
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
redux: 'Redux',
|
||||
'react-redux': 'ReactRedux',
|
||||
'prop-types': 'PropTypes',
|
||||
'react-bootstrap': 'ReactBootstrap',
|
||||
'react-router-dom': 'ReactRouterDom',
|
||||
'react-intl': 'ReactIntl',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
server: {
|
||||
port: 3001,
|
||||
cors: true,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
// ----------------------------------------------------
|
||||
// HMR-настройка для плагина, загружаемого в Loop
|
||||
hmr: {
|
||||
protocol: 'ws', // WebSocket
|
||||
host: 'localhost', // где запущен vite dev
|
||||
port: 3001, // тот же порт
|
||||
clientPort: 3001, // куда клиент будет подключаться
|
||||
},
|
||||
// ----------------------------------------------------
|
||||
},
|
||||
|
||||
define: {
|
||||
__PLUGIN_DEV__: isDev,
|
||||
__PLUGIN_COMPONENTS_HOST__: isDev
|
||||
? JSON.stringify('http://localhost:3001')
|
||||
: JSON.stringify(null),
|
||||
},
|
||||
});
|
||||
+7063
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user