@openedx/frontend-base 1.0.0-alpha.1 → 1.0.0-alpha.10
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/config/eslint/base.eslint.config.js +1 -1
- package/config/jest/jest.config.js +1 -0
- package/config/types.js +0 -2
- package/config/webpack/common-config/all/getStylesheetRule.js +1 -1
- package/config/webpack/webpack.config.build.js +1 -11
- package/config/webpack/webpack.config.dev.js +5 -11
- package/config/webpack/webpack.config.dev.shell.js +5 -11
- package/package.json +4 -3
- package/runtime/config/index.ts +2 -3
- package/runtime/index.ts +5 -0
- package/runtime/jest.config.js +1 -0
- package/runtime/react/SiteProvider.tsx +26 -3
- package/runtime/react/constants.ts +3 -0
- package/runtime/react/hooks/index.ts +8 -0
- package/runtime/react/hooks/theme/index.ts +2 -0
- package/runtime/react/hooks/theme/useTheme.test.ts +221 -0
- package/runtime/react/hooks/theme/useTheme.ts +179 -0
- package/runtime/react/hooks/theme/useThemeConfig.test.ts +107 -0
- package/runtime/react/hooks/theme/useThemeConfig.ts +34 -0
- package/runtime/react/hooks/theme/useThemeCore.test.ts +65 -0
- package/runtime/react/hooks/theme/useThemeCore.ts +52 -0
- package/runtime/react/hooks/theme/useThemeVariants.test.ts +97 -0
- package/runtime/react/hooks/theme/useThemeVariants.ts +116 -0
- package/runtime/react/hooks/theme/useTrackColorSchemeChoice.test.ts +54 -0
- package/runtime/react/hooks/theme/useTrackColorSchemeChoice.ts +30 -0
- package/runtime/react/hooks/theme/utils.ts +11 -0
- package/runtime/react/hooks/useActiveRoles.ts +15 -0
- package/runtime/react/hooks/useActiveRouteRoleWatcher.ts +31 -0
- package/runtime/react/hooks/useAppConfig.ts +9 -0
- package/runtime/react/hooks/useAuthenticatedUser.test.tsx +41 -0
- package/runtime/react/hooks/useAuthenticatedUser.ts +9 -0
- package/runtime/react/hooks/useSiteConfig.test.tsx +13 -0
- package/runtime/react/hooks/useSiteConfig.ts +9 -0
- package/runtime/react/hooks/useSiteEvent.ts +24 -0
- package/runtime/react/reducers.ts +40 -0
- package/runtime/setupTest.js +0 -35
- package/runtime/slots/widget/iframe/hooks.ts +1 -1
- package/runtime/testing/initializeMockApp.ts +5 -0
- package/shell/app.scss +2 -1
- package/shell/jest.config.js +1 -0
- package/shell/setupTest.js +0 -35
- package/shell/site.tsx +1 -1
- package/tools/dist/cli/openedx.js +1 -15
- package/tools/dist/cli/utils/printUsage.js +0 -9
- package/tools/dist/eslint/base.eslint.config.js +1 -1
- package/tools/dist/jest/jest.config.js +1 -0
- package/tools/dist/types.js +0 -2
- package/tools/dist/webpack/common-config/all/getStylesheetRule.js +1 -1
- package/tools/dist/webpack/webpack.config.build.js +1 -11
- package/tools/dist/webpack/webpack.config.dev.js +5 -11
- package/tools/dist/webpack/webpack.config.dev.shell.js +5 -11
- package/types.ts +20 -0
- package/config/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +0 -108
- package/config/webpack/plugins/paragon-webpack-plugin/index.js +0 -7
- package/config/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +0 -64
- package/config/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +0 -53
- package/config/webpack/plugins/paragon-webpack-plugin/utils/index.js +0 -9
- package/config/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +0 -114
- package/config/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +0 -146
- package/config/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +0 -126
- package/config/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +0 -57
- package/config/webpack/types.js +0 -2
- package/config/webpack/utils/paragonUtils.js +0 -138
- package/runtime/react/hooks.test.jsx +0 -104
- package/runtime/react/hooks.ts +0 -106
- package/tools/dist/cli/commands/pack.js +0 -14
- package/tools/dist/cli/commands/release.js +0 -28
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +0 -108
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/index.js +0 -7
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +0 -64
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +0 -53
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/index.js +0 -9
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +0 -114
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +0 -146
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +0 -126
- package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +0 -57
- package/tools/dist/webpack/types.js +0 -2
- package/tools/dist/webpack/utils/paragonUtils.js +0 -138
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { sendTrackEvent } from '../../../analytics';
|
|
3
|
+
import useTrackColorSchemeChoice from './useTrackColorSchemeChoice';
|
|
4
|
+
|
|
5
|
+
jest.mock('../../../analytics');
|
|
6
|
+
|
|
7
|
+
const mockAddEventListener = jest.fn();
|
|
8
|
+
const mockRemoveEventListener = jest.fn();
|
|
9
|
+
let matchesMock;
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
12
|
+
value: jest.fn(() => ({
|
|
13
|
+
addEventListener: mockAddEventListener,
|
|
14
|
+
removeEventListener: mockRemoveEventListener,
|
|
15
|
+
matches: matchesMock,
|
|
16
|
+
})),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('useTrackColorSchemeChoice hook', () => {
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
mockAddEventListener.mockClear();
|
|
22
|
+
mockRemoveEventListener.mockClear();
|
|
23
|
+
jest.mocked(sendTrackEvent).mockClear();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('sends dark preferred color schema event if query matches', async () => {
|
|
27
|
+
matchesMock = true;
|
|
28
|
+
renderHook(() => useTrackColorSchemeChoice());
|
|
29
|
+
|
|
30
|
+
expect(sendTrackEvent).toHaveBeenCalledTimes(1);
|
|
31
|
+
expect(sendTrackEvent).toHaveBeenCalledWith(
|
|
32
|
+
'openedx.ui.frontend-base.prefers-color-scheme.selected',
|
|
33
|
+
{ preferredColorScheme: 'dark' },
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('sends light preferred color schema event if query does not match', async () => {
|
|
38
|
+
matchesMock = false;
|
|
39
|
+
renderHook(() => useTrackColorSchemeChoice());
|
|
40
|
+
|
|
41
|
+
expect(sendTrackEvent).toHaveBeenCalledTimes(1);
|
|
42
|
+
expect(sendTrackEvent).toHaveBeenCalledWith(
|
|
43
|
+
'openedx.ui.frontend-base.prefers-color-scheme.selected',
|
|
44
|
+
{ preferredColorScheme: 'light' },
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('adds change event listener to matchMedia query', async () => {
|
|
49
|
+
renderHook(() => useTrackColorSchemeChoice());
|
|
50
|
+
|
|
51
|
+
expect(mockAddEventListener).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(mockAddEventListener).toHaveBeenCalledWith('change', expect.any(Function));
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { sendTrackEvent } from '../../../analytics';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A React hook that tracks user's preferred color scheme (light or dark) and sends respective
|
|
6
|
+
* event to the tracking service.
|
|
7
|
+
*
|
|
8
|
+
* @memberof module:React
|
|
9
|
+
*/
|
|
10
|
+
const useTrackColorSchemeChoice = () => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const trackColorSchemeChoice = ({ matches }) => {
|
|
13
|
+
const preferredColorScheme = matches ? 'dark' : 'light';
|
|
14
|
+
sendTrackEvent('openedx.ui.frontend-base.prefers-color-scheme.selected', { preferredColorScheme });
|
|
15
|
+
};
|
|
16
|
+
const colorSchemeQuery = window.matchMedia?.('(prefers-color-scheme: dark)');
|
|
17
|
+
if (colorSchemeQuery) {
|
|
18
|
+
// send user's initial choice
|
|
19
|
+
trackColorSchemeChoice(colorSchemeQuery);
|
|
20
|
+
colorSchemeQuery.addEventListener('change', trackColorSchemeChoice);
|
|
21
|
+
}
|
|
22
|
+
return () => {
|
|
23
|
+
if (colorSchemeQuery) {
|
|
24
|
+
colorSchemeQuery.removeEventListener('change', trackColorSchemeChoice);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}, []);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default useTrackColorSchemeChoice;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterates through each given `<link>` element and removes it from the DOM.
|
|
3
|
+
* @param {HTMLLinkElement[]} existingLinks
|
|
4
|
+
*/
|
|
5
|
+
export const removeExistingLinks = (existingLinks) => {
|
|
6
|
+
existingLinks.forEach((link) => {
|
|
7
|
+
link.remove();
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const isEmptyObject = (obj) => !obj || Object.keys(obj).length === 0;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { getActiveRoles } from '../../config';
|
|
3
|
+
import { ACTIVE_ROLES_CHANGED } from '../../constants';
|
|
4
|
+
import useSiteEvent from './useSiteEvent';
|
|
5
|
+
|
|
6
|
+
const useActiveRoles = () => {
|
|
7
|
+
const [roles, setRoles] = useState<string[]>(getActiveRoles());
|
|
8
|
+
useSiteEvent(ACTIVE_ROLES_CHANGED, () => {
|
|
9
|
+
setRoles(getActiveRoles());
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return roles;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default useActiveRoles;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { useMatches } from 'react-router';
|
|
3
|
+
import { setActiveRouteRoles } from '../../config';
|
|
4
|
+
import { isRoleRouteObject } from '../../routing';
|
|
5
|
+
|
|
6
|
+
const useActiveRouteRoleWatcher = () => {
|
|
7
|
+
const matches = useMatches();
|
|
8
|
+
|
|
9
|
+
// We create this callback so we can use it right away to populate the default state value.
|
|
10
|
+
const findActiveRouteRoles = useCallback(() => {
|
|
11
|
+
// Starts with the widget roles and adds the others in.
|
|
12
|
+
const roles: string[] = [];
|
|
13
|
+
|
|
14
|
+
// Route roles
|
|
15
|
+
for (const match of matches) {
|
|
16
|
+
if (isRoleRouteObject(match)) {
|
|
17
|
+
if (!roles.includes(match.handle.role)) {
|
|
18
|
+
roles.push(match.handle.role);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return roles;
|
|
24
|
+
}, [matches]);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
setActiveRouteRoles(findActiveRouteRoles());
|
|
28
|
+
}, [matches, findActiveRouteRoles]);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default useActiveRouteRoleWatcher;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react';
|
|
2
|
+
import { setAuthenticatedUser } from '../../auth';
|
|
3
|
+
import { initializeMockApp } from '../../testing';
|
|
4
|
+
import SiteProvider from '../SiteProvider';
|
|
5
|
+
import useAuthenticatedUser from './useAuthenticatedUser';
|
|
6
|
+
|
|
7
|
+
describe('useAuthenticatedUser', () => {
|
|
8
|
+
it('returns null when the user is anonymous', () => {
|
|
9
|
+
const { result } = renderHook(() => useAuthenticatedUser());
|
|
10
|
+
expect(result.current).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('with a user', () => {
|
|
14
|
+
const user = {
|
|
15
|
+
administrator: true,
|
|
16
|
+
email: 'admin@example.com',
|
|
17
|
+
name: 'Admin',
|
|
18
|
+
roles: ['admin'],
|
|
19
|
+
userId: 1,
|
|
20
|
+
username: 'admin-user',
|
|
21
|
+
avatar: 'http://localhost/admin.png',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
initializeMockApp({
|
|
26
|
+
authenticatedUser: user,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
act(() => {
|
|
32
|
+
setAuthenticatedUser(null);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('returns a User when the user exists', () => {
|
|
37
|
+
const { result } = renderHook(() => useAuthenticatedUser(), { wrapper: SiteProvider });
|
|
38
|
+
expect(result.current).toBe(user);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import siteConfig from 'site.config';
|
|
3
|
+
import { EnvironmentTypes } from '../../../types';
|
|
4
|
+
import useSiteConfig from './useSiteConfig';
|
|
5
|
+
|
|
6
|
+
describe('useSiteConfig', () => {
|
|
7
|
+
it('returns the site config', () => {
|
|
8
|
+
const { result } = renderHook(() => useSiteConfig());
|
|
9
|
+
expect(result.current).toHaveProperty('apps', siteConfig.apps);
|
|
10
|
+
expect(result.current).toHaveProperty('environment', EnvironmentTypes.TEST);
|
|
11
|
+
expect(result.current).toHaveProperty('baseUrl', 'http://localhost:8080');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { subscribe, unsubscribe } from '../../subscriptions';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A React hook that allows functional components to subscribe to application events. This should
|
|
6
|
+
* be used sparingly - for the most part, Context should be used higher-up in the application to
|
|
7
|
+
* provide necessary data to a given component, rather than utilizing a non-React-like Pub/Sub
|
|
8
|
+
* mechanism.
|
|
9
|
+
*
|
|
10
|
+
* @memberof module:React
|
|
11
|
+
* @param {string} type
|
|
12
|
+
* @param {function} callback
|
|
13
|
+
*/
|
|
14
|
+
const useSiteEvent = (type, callback) => {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
subscribe(type, callback);
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
unsubscribe(type, callback);
|
|
20
|
+
};
|
|
21
|
+
}, [callback, type]);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default useSiteEvent;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SET_THEME_VARIANT,
|
|
3
|
+
SET_IS_THEME_LOADED,
|
|
4
|
+
} from './constants';
|
|
5
|
+
|
|
6
|
+
export function themeReducer(state, action) {
|
|
7
|
+
switch (action.type) {
|
|
8
|
+
case SET_THEME_VARIANT: {
|
|
9
|
+
const requestedThemeVariant = action.payload;
|
|
10
|
+
return {
|
|
11
|
+
...state,
|
|
12
|
+
themeVariant: requestedThemeVariant,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
case SET_IS_THEME_LOADED: {
|
|
16
|
+
const requestedIsThemeLoaded = action.payload;
|
|
17
|
+
return {
|
|
18
|
+
...state,
|
|
19
|
+
isThemeLoaded: requestedIsThemeLoaded,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
return state;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const setThemeVariant = (payload) => ({
|
|
28
|
+
type: SET_THEME_VARIANT,
|
|
29
|
+
payload,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const setThemeLoaded = (payload) => ({
|
|
33
|
+
type: SET_IS_THEME_LOADED,
|
|
34
|
+
payload,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const themeActions = {
|
|
38
|
+
setThemeVariant,
|
|
39
|
+
setThemeLoaded,
|
|
40
|
+
};
|
package/runtime/setupTest.js
CHANGED
|
@@ -12,38 +12,3 @@ jest.mock('universal-cookie', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
mergeSiteConfig(siteConfig);
|
|
15
|
-
|
|
16
|
-
global.PARAGON_THEME = {
|
|
17
|
-
paragon: {
|
|
18
|
-
version: '1.0.0',
|
|
19
|
-
themeUrls: {
|
|
20
|
-
core: {
|
|
21
|
-
fileName: 'core.min.css',
|
|
22
|
-
},
|
|
23
|
-
defaults: {
|
|
24
|
-
light: 'light',
|
|
25
|
-
},
|
|
26
|
-
variants: {
|
|
27
|
-
light: {
|
|
28
|
-
fileName: 'light.min.css',
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
brand: {
|
|
34
|
-
version: '1.0.0',
|
|
35
|
-
themeUrls: {
|
|
36
|
-
core: {
|
|
37
|
-
fileName: 'core.min.css',
|
|
38
|
-
},
|
|
39
|
-
defaults: {
|
|
40
|
-
light: 'light',
|
|
41
|
-
},
|
|
42
|
-
variants: {
|
|
43
|
-
light: {
|
|
44
|
-
fileName: 'light.min.css',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
@@ -127,7 +127,7 @@ export function dispatchUnmountedEvent() {
|
|
|
127
127
|
*/
|
|
128
128
|
export function useElementSize() {
|
|
129
129
|
// Holds a reference to the ResizeObserver
|
|
130
|
-
const observerRef = useRef<ResizeObserver>();
|
|
130
|
+
const observerRef = useRef<ResizeObserver | null>(null);
|
|
131
131
|
|
|
132
132
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
|
133
133
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import siteConfig from 'site.config';
|
|
2
2
|
|
|
3
|
+
import { LocalizedMessages, User } from '../../types';
|
|
4
|
+
|
|
3
5
|
import { configureAnalytics, MockAnalyticsService } from '../analytics';
|
|
4
6
|
import { configureAuth, MockAuthService, setAuthenticatedUser } from '../auth';
|
|
5
7
|
import { getSiteConfig, mergeSiteConfig } from '../config';
|
|
@@ -47,6 +49,9 @@ import mockMessages from './mockMessages';
|
|
|
47
49
|
export default function initializeMockApp({
|
|
48
50
|
messages = mockMessages,
|
|
49
51
|
authenticatedUser = null,
|
|
52
|
+
}: {
|
|
53
|
+
messages?: LocalizedMessages,
|
|
54
|
+
authenticatedUser?: User | null,
|
|
50
55
|
} = {}) {
|
|
51
56
|
const config = siteConfig;
|
|
52
57
|
mergeSiteConfig(config);
|
package/shell/app.scss
CHANGED
package/shell/jest.config.js
CHANGED
|
@@ -7,6 +7,7 @@ module.exports = {
|
|
|
7
7
|
'\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/file.js',
|
|
8
8
|
'\\.(css|scss)$': require.resolve('identity-obj-proxy'),
|
|
9
9
|
'site.config': '<rootDir>/site.config.test.tsx',
|
|
10
|
+
'^@src/(.*)$': '<rootDir>/src/$1',
|
|
10
11
|
},
|
|
11
12
|
testEnvironment: 'jsdom',
|
|
12
13
|
testEnvironmentOptions: {
|
package/shell/setupTest.js
CHANGED
|
@@ -11,38 +11,3 @@ jest.mock('universal-cookie', () => {
|
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
mergeSiteConfig(siteConfig);
|
|
14
|
-
|
|
15
|
-
global.PARAGON_THEME = {
|
|
16
|
-
paragon: {
|
|
17
|
-
version: '1.0.0',
|
|
18
|
-
themeUrls: {
|
|
19
|
-
core: {
|
|
20
|
-
fileName: 'core.min.css',
|
|
21
|
-
},
|
|
22
|
-
defaults: {
|
|
23
|
-
light: 'light',
|
|
24
|
-
},
|
|
25
|
-
variants: {
|
|
26
|
-
light: {
|
|
27
|
-
fileName: 'light.min.css',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
brand: {
|
|
33
|
-
version: '1.0.0',
|
|
34
|
-
themeUrls: {
|
|
35
|
-
core: {
|
|
36
|
-
fileName: 'core.min.css',
|
|
37
|
-
},
|
|
38
|
-
defaults: {
|
|
39
|
-
light: 'light',
|
|
40
|
-
},
|
|
41
|
-
variants: {
|
|
42
|
-
light: {
|
|
43
|
-
fileName: 'light.min.css',
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
};
|
package/shell/site.tsx
CHANGED
|
@@ -8,8 +8,6 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const fs_1 = require("fs");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const types_1 = require("../types");
|
|
11
|
-
const pack_1 = __importDefault(require("./commands/pack"));
|
|
12
|
-
const release_1 = __importDefault(require("./commands/release"));
|
|
13
11
|
const ensureConfigFilenameOption_1 = require("./utils/ensureConfigFilenameOption");
|
|
14
12
|
const prettyPrintTitle_1 = __importDefault(require("./utils/prettyPrintTitle"));
|
|
15
13
|
const printUsage_1 = __importDefault(require("./utils/printUsage"));
|
|
@@ -26,18 +24,6 @@ else if ((0, fs_1.existsSync)(path_1.default.resolve(__dirname, '../../../packag
|
|
|
26
24
|
}
|
|
27
25
|
(0, prettyPrintTitle_1.default)(`Open edX CLI v${version}`);
|
|
28
26
|
switch (commandName) {
|
|
29
|
-
case types_1.CommandTypes.RELEASE:
|
|
30
|
-
(0, release_1.default)();
|
|
31
|
-
break;
|
|
32
|
-
case types_1.CommandTypes.PACK:
|
|
33
|
-
if (process.argv[2] === undefined) {
|
|
34
|
-
console.log(chalk_1.default.red(`${chalk_1.default.bold.red(commandName)} command usage: specify a peer folder where the command should install the package:
|
|
35
|
-
|
|
36
|
-
npm run pack my-project`));
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
(0, pack_1.default)();
|
|
40
|
-
break;
|
|
41
27
|
case types_1.CommandTypes.LINT:
|
|
42
28
|
(0, ensureConfigFilenameOption_1.ensureConfigFilenameOption)(types_1.ConfigTypes.LINT, ['-c', '--config']);
|
|
43
29
|
require('.bin/eslint');
|
|
@@ -78,7 +64,7 @@ switch (commandName) {
|
|
|
78
64
|
srcFoldersString = `{${srcFoldersString}}`;
|
|
79
65
|
}
|
|
80
66
|
process.argv = process.argv.concat([
|
|
81
|
-
'--format', 'node_modules/@openedx/frontend-base/dist/
|
|
67
|
+
'--format', 'node_modules/@openedx/frontend-base/tools/dist/cli/utils/formatter.js',
|
|
82
68
|
'--ignore', `${srcFoldersString}/**/*.json`,
|
|
83
69
|
'--ignore', `${srcFoldersString}/**/*.d.ts`,
|
|
84
70
|
'--out-file', './temp/formatjs/Default.messages.json',
|
|
@@ -11,15 +11,6 @@ function printUsage() {
|
|
|
11
11
|
console.log('openedx <command> <options>\n');
|
|
12
12
|
console.groupEnd();
|
|
13
13
|
console.log('Commands:\n');
|
|
14
|
-
console.group();
|
|
15
|
-
console.log(`${chalk_1.default.bold('release')}\n`);
|
|
16
|
-
console.group();
|
|
17
|
-
console.log(`Compile source code for release as a library. Compiled code is put into the dist folder.\n`);
|
|
18
|
-
console.groupEnd();
|
|
19
|
-
console.log(`${chalk_1.default.bold('pack')} <peer folder>\n`);
|
|
20
|
-
console.group();
|
|
21
|
-
console.log(`Package the dist folder as an NPM-compatible .tgz file suitable for use with npm install, then install it in the specified peer folder. The folder is assumed to be a peer of this repository, do not include a path.\n`);
|
|
22
|
-
console.groupEnd();
|
|
23
14
|
console.log(`${chalk_1.default.bold('lint')} <eslint options>\n`);
|
|
24
15
|
console.group();
|
|
25
16
|
console.log(`Runs ESLint on the source code. Requires an ${chalk_1.default.bold('eslint.config.js')} file.\n`);
|
|
@@ -31,7 +31,6 @@ module.exports = tseslint.config(eslint.configs.recommended, ...tseslint.configs
|
|
|
31
31
|
...globals.browser,
|
|
32
32
|
...globals.node,
|
|
33
33
|
...globals.jest,
|
|
34
|
-
PARAGON_THEME: 'readonly',
|
|
35
34
|
newrelic: 'readonly',
|
|
36
35
|
},
|
|
37
36
|
},
|
|
@@ -79,6 +78,7 @@ module.exports = tseslint.config(eslint.configs.recommended, ...tseslint.configs
|
|
|
79
78
|
caughtErrors: 'none',
|
|
80
79
|
}],
|
|
81
80
|
'@typescript-eslint/no-empty-function': 'off',
|
|
81
|
+
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
|
82
82
|
'@stylistic/semi': ['error', 'always', { omitLastInOneLineBlock: true, omitLastInOneLineClassBody: true }],
|
|
83
83
|
'@stylistic/quotes': ['error', 'single', {
|
|
84
84
|
avoidEscape: true,
|
|
@@ -9,6 +9,7 @@ module.exports = {
|
|
|
9
9
|
moduleNameMapper: {
|
|
10
10
|
'\\.(css|scss)$': require.resolve('identity-obj-proxy'),
|
|
11
11
|
'site.config': path.resolve(process.cwd(), './site.config.test.tsx'),
|
|
12
|
+
'^@src/(.*)$': '<rootDir>/src/$1',
|
|
12
13
|
},
|
|
13
14
|
collectCoverageFrom: [
|
|
14
15
|
'src/**/*.{js,jsx,ts,tsx}',
|
package/tools/dist/types.js
CHANGED
|
@@ -12,8 +12,6 @@ var ConfigTypes;
|
|
|
12
12
|
})(ConfigTypes || (exports.ConfigTypes = ConfigTypes = {}));
|
|
13
13
|
var CommandTypes;
|
|
14
14
|
(function (CommandTypes) {
|
|
15
|
-
CommandTypes["RELEASE"] = "release";
|
|
16
|
-
CommandTypes["PACK"] = "pack";
|
|
17
15
|
CommandTypes["LINT"] = "lint";
|
|
18
16
|
CommandTypes["TEST"] = "test";
|
|
19
17
|
CommandTypes["BUILD"] = "build";
|
|
@@ -87,7 +87,7 @@ function getStyleUseConfig(mode) {
|
|
|
87
87
|
],
|
|
88
88
|
// Silences compiler deprecation warnings. They mostly come from bootstrap and/or paragon.
|
|
89
89
|
quietDeps: true,
|
|
90
|
-
silenceDeprecations: ['abs-percent', 'color-functions', 'import', '
|
|
90
|
+
silenceDeprecations: ['abs-percent', 'color-functions', 'import', 'global-builtin', 'legacy-js-api'],
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
93
|
},
|
|
@@ -9,13 +9,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
|
|
10
10
|
const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
|
|
11
11
|
const common_config_1 = require("./common-config");
|
|
12
|
-
const ParagonWebpackPlugin_1 = __importDefault(require("./plugins/paragon-webpack-plugin/ParagonWebpackPlugin"));
|
|
13
12
|
const getLocalAliases_1 = __importDefault(require("./utils/getLocalAliases"));
|
|
14
13
|
const getPublicPath_1 = __importDefault(require("./utils/getPublicPath"));
|
|
15
14
|
const getResolvedSiteConfigPath_1 = __importDefault(require("./utils/getResolvedSiteConfigPath"));
|
|
16
|
-
const paragonUtils_1 = require("./utils/paragonUtils");
|
|
17
|
-
const paragonThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd());
|
|
18
|
-
const brandThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd(), { isBrandOverride: true });
|
|
19
15
|
const aliases = (0, getLocalAliases_1.default)();
|
|
20
16
|
const resolvedSiteConfigPath = (0, getResolvedSiteConfigPath_1.default)('site.config.build.tsx');
|
|
21
17
|
const config = {
|
|
@@ -23,8 +19,6 @@ const config = {
|
|
|
23
19
|
devtool: 'source-map',
|
|
24
20
|
entry: {
|
|
25
21
|
app: path_1.default.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/shell/site'),
|
|
26
|
-
...(0, paragonUtils_1.getParagonEntryPoints)(paragonThemeCss),
|
|
27
|
-
...(0, paragonUtils_1.getParagonEntryPoints)(brandThemeCss),
|
|
28
22
|
},
|
|
29
23
|
output: {
|
|
30
24
|
filename: '[name].[chunkhash].js',
|
|
@@ -36,6 +30,7 @@ const config = {
|
|
|
36
30
|
alias: {
|
|
37
31
|
...aliases,
|
|
38
32
|
'site.config': resolvedSiteConfigPath,
|
|
33
|
+
'@src': path_1.default.resolve(process.cwd(), 'src'),
|
|
39
34
|
},
|
|
40
35
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
41
36
|
},
|
|
@@ -51,10 +46,6 @@ const config = {
|
|
|
51
46
|
runtimeChunk: 'single',
|
|
52
47
|
splitChunks: {
|
|
53
48
|
chunks: 'all',
|
|
54
|
-
cacheGroups: {
|
|
55
|
-
...(0, paragonUtils_1.getParagonCacheGroups)(paragonThemeCss),
|
|
56
|
-
...(0, paragonUtils_1.getParagonCacheGroups)(brandThemeCss),
|
|
57
|
-
},
|
|
58
49
|
},
|
|
59
50
|
minimizer: (0, common_config_1.getImageMinimizer)(),
|
|
60
51
|
},
|
|
@@ -65,7 +56,6 @@ const config = {
|
|
|
65
56
|
// See: https://www.npmjs.com/package/webpack-remove-empty-scripts#usage-with-mini-css-extract-plugin
|
|
66
57
|
new webpack_remove_empty_scripts_1.default(),
|
|
67
58
|
// Writes the extracted CSS from each entry to a file in the output directory.
|
|
68
|
-
new ParagonWebpackPlugin_1.default(),
|
|
69
59
|
new mini_css_extract_plugin_1.default({
|
|
70
60
|
filename: '[name].[chunkhash].css',
|
|
71
61
|
}),
|
|
@@ -9,20 +9,14 @@ const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plug
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
|
|
11
11
|
const common_config_1 = require("./common-config");
|
|
12
|
-
const ParagonWebpackPlugin_1 = __importDefault(require("./plugins/paragon-webpack-plugin/ParagonWebpackPlugin"));
|
|
13
12
|
const getLocalAliases_1 = __importDefault(require("./utils/getLocalAliases"));
|
|
14
13
|
const getPublicPath_1 = __importDefault(require("./utils/getPublicPath"));
|
|
15
14
|
const getResolvedSiteConfigPath_1 = __importDefault(require("./utils/getResolvedSiteConfigPath"));
|
|
16
|
-
const paragonUtils_1 = require("./utils/paragonUtils");
|
|
17
|
-
const paragonThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd());
|
|
18
|
-
const brandThemeCss = (0, paragonUtils_1.getParagonThemeCss)(process.cwd(), { isBrandOverride: true });
|
|
19
15
|
const aliases = (0, getLocalAliases_1.default)();
|
|
20
16
|
const resolvedSiteConfigPath = (0, getResolvedSiteConfigPath_1.default)('site.config.dev.tsx');
|
|
21
17
|
const config = {
|
|
22
18
|
entry: {
|
|
23
19
|
app: path_1.default.resolve(process.cwd(), 'node_modules/@openedx/frontend-base/shell/site'),
|
|
24
|
-
...(0, paragonUtils_1.getParagonEntryPoints)(paragonThemeCss),
|
|
25
|
-
...(0, paragonUtils_1.getParagonEntryPoints)(brandThemeCss),
|
|
26
20
|
},
|
|
27
21
|
output: {
|
|
28
22
|
path: path_1.default.resolve(process.cwd(), './dist'),
|
|
@@ -32,6 +26,7 @@ const config = {
|
|
|
32
26
|
alias: {
|
|
33
27
|
...aliases,
|
|
34
28
|
'site.config': resolvedSiteConfigPath,
|
|
29
|
+
'@src': path_1.default.resolve(process.cwd(), 'src'),
|
|
35
30
|
},
|
|
36
31
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
37
32
|
},
|
|
@@ -47,10 +42,6 @@ const config = {
|
|
|
47
42
|
optimization: {
|
|
48
43
|
splitChunks: {
|
|
49
44
|
chunks: 'all',
|
|
50
|
-
cacheGroups: {
|
|
51
|
-
...(0, paragonUtils_1.getParagonCacheGroups)(paragonThemeCss),
|
|
52
|
-
...(0, paragonUtils_1.getParagonCacheGroups)(brandThemeCss),
|
|
53
|
-
},
|
|
54
45
|
},
|
|
55
46
|
minimizer: (0, common_config_1.getImageMinimizer)(),
|
|
56
47
|
},
|
|
@@ -60,7 +51,6 @@ const config = {
|
|
|
60
51
|
// This helps to clean up the final bundle application
|
|
61
52
|
// See: https://www.npmjs.com/package/webpack-remove-empty-scripts#usage-with-mini-css-extract-plugin
|
|
62
53
|
new webpack_remove_empty_scripts_1.default(),
|
|
63
|
-
new ParagonWebpackPlugin_1.default(),
|
|
64
54
|
// Writes the extracted CSS from each entry to a file in the output directory.
|
|
65
55
|
new mini_css_extract_plugin_1.default({
|
|
66
56
|
filename: '[name].css',
|
|
@@ -72,5 +62,9 @@ const config = {
|
|
|
72
62
|
// This configures webpack-dev-server which serves bundles from memory and provides live
|
|
73
63
|
// reloading.
|
|
74
64
|
devServer: (0, common_config_1.getDevServer)(),
|
|
65
|
+
// Limit the number of watched files to avoid `inotify` resource starvation.
|
|
66
|
+
watchOptions: {
|
|
67
|
+
ignored: /node_modules/
|
|
68
|
+
}
|
|
75
69
|
};
|
|
76
70
|
exports.default = config;
|