5htp 0.0.6 → 0.0.8
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/package.json +4 -2
- package/readme.md +30 -0
- package/skeleton/.github/workflows/ci.yml +93 -0
- package/skeleton/.github/workflows/ecs-task.json +77 -0
- package/skeleton/Dockerfile +20 -0
- package/skeleton/docker-compose.yml +45 -0
- package/skeleton/identity.yaml +17 -0
- package/skeleton/package-lock.json +6139 -0
- package/skeleton/package.json +30 -0
- package/skeleton/src/client/assets/identity/logo.svg +64 -0
- package/skeleton/src/client/assets/identity/logoAndText.svg +105 -0
- package/skeleton/src/client/assets/illustration/launch.jpg +0 -0
- package/skeleton/src/client/assets/logos/google-play-store.svg +1 -0
- package/skeleton/src/client/assets/logos/googleauth.svg +9 -0
- package/skeleton/src/client/assets/patterns/interlaced.png +0 -0
- package/skeleton/src/client/assets/theme.less +278 -0
- package/skeleton/src/client/components/LoginModal.tsx +45 -0
- package/skeleton/src/client/pages/app/_layout/index.less +20 -0
- package/skeleton/src/client/pages/app/_layout/index.tsx +33 -0
- package/skeleton/src/client/pages/app/index.tsx +57 -0
- package/skeleton/src/client/pages/landing/_layout/index.less +145 -0
- package/skeleton/src/client/pages/landing/_layout/index.tsx +63 -0
- package/skeleton/src/client/pages/landing/index.tsx +73 -0
- package/skeleton/src/client/pages/preload.json +3 -0
- package/skeleton/src/client/tsconfig.json +32 -0
- package/skeleton/src/common/tsconfig.json +10 -0
- package/skeleton/src/server/config.ts +125 -0
- package/skeleton/src/server/index.ts +23 -0
- package/skeleton/src/server/routes/general.ts +66 -0
- package/skeleton/src/server/services/auth/index.ts +88 -0
- package/skeleton/src/server/tsconfig.json +34 -0
- package/src/{utils → app}/config.ts +20 -2
- package/src/app/index.ts +75 -0
- package/src/commands/build.ts +6 -1
- package/src/commands/deploy/web.ts +3 -3
- package/src/commands/dev.ts +11 -9
- package/src/commands/init.ts +85 -0
- package/src/compiler/client/identite.ts +7 -5
- package/src/compiler/client/index.ts +21 -18
- package/src/compiler/common/babel/index.ts +209 -201
- package/src/compiler/common/babel/plugins/injection-dependances/index.ts +2 -2
- package/src/compiler/common/babel/plugins/pages.ts +4 -2
- package/src/compiler/common/files/autres.ts +3 -1
- package/src/compiler/common/files/images.ts +2 -1
- package/src/compiler/common/files/style.ts +6 -4
- package/src/compiler/common/index.ts +13 -7
- package/src/compiler/common/plugins/indexage/icones-svg/index.ts +45 -37
- package/src/compiler/common/plugins/indexage/injection-dependances/index.ts +1 -1
- package/src/compiler/index.ts +24 -3
- package/src/compiler/server/index.ts +19 -19
- package/src/index.ts +4 -18
- package/src/paths.ts +12 -33
- package/tsconfig.json +1 -2
package/src/app/index.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// npm
|
|
6
|
+
import TsAlias from 'ts-alias';
|
|
7
|
+
|
|
8
|
+
// Cre
|
|
9
|
+
import cli from '..';
|
|
10
|
+
|
|
11
|
+
// Specific
|
|
12
|
+
import ConfigParser from './config';
|
|
13
|
+
|
|
14
|
+
/*----------------------------------
|
|
15
|
+
- TYPES
|
|
16
|
+
----------------------------------*/
|
|
17
|
+
|
|
18
|
+
export type TAppSide = 'server' | 'client'
|
|
19
|
+
|
|
20
|
+
/*----------------------------------
|
|
21
|
+
- SERVICE
|
|
22
|
+
----------------------------------*/
|
|
23
|
+
export default class App {
|
|
24
|
+
|
|
25
|
+
// config
|
|
26
|
+
// WARNING: High level config files (env and services) shouldn't be loaded from the CLI
|
|
27
|
+
// The CLI will be run on CircleCI, and no env file should be sent to this service
|
|
28
|
+
public identity!: Core.Config.Identity;
|
|
29
|
+
|
|
30
|
+
public paths = {
|
|
31
|
+
root: cli.paths.appRoot,
|
|
32
|
+
src: cli.paths.appRoot + '/src',
|
|
33
|
+
bin: cli.paths.appRoot + '/bin',
|
|
34
|
+
data: cli.paths.appRoot + '/var/data',
|
|
35
|
+
public: cli.paths.appRoot + '/public',
|
|
36
|
+
pages: cli.paths.appRoot + '/src/client/pages',
|
|
37
|
+
cache: cli.paths.appRoot + '/src/.cache',
|
|
38
|
+
|
|
39
|
+
withAlias: (filename: string, side: TAppSide) =>
|
|
40
|
+
this.aliases[side].apply(filename),
|
|
41
|
+
|
|
42
|
+
withoutAlias: (filename: string, side: TAppSide) =>
|
|
43
|
+
this.aliases[side].realpath(filename),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public constructor() {
|
|
47
|
+
|
|
48
|
+
console.log(`[cli] Loading app config ...`);
|
|
49
|
+
const configParser = new ConfigParser( cli.paths.appRoot );
|
|
50
|
+
this.identity = configParser.identity();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*----------------------------------
|
|
54
|
+
- ALIAS
|
|
55
|
+
----------------------------------*/
|
|
56
|
+
|
|
57
|
+
public aliases = {
|
|
58
|
+
client: new TsAlias({
|
|
59
|
+
rootDir: this.paths.root + '/src/client',
|
|
60
|
+
modulesDir: [
|
|
61
|
+
cli.paths.appRoot + '/node_modules',
|
|
62
|
+
cli.paths.coreRoot + '/node_modules'
|
|
63
|
+
],
|
|
64
|
+
debug: false
|
|
65
|
+
}),
|
|
66
|
+
server: new TsAlias({
|
|
67
|
+
rootDir: this.paths.root + '/src/server',
|
|
68
|
+
modulesDir: [
|
|
69
|
+
cli.paths.appRoot + '/node_modules',
|
|
70
|
+
cli.paths.coreRoot + '/node_modules'
|
|
71
|
+
],
|
|
72
|
+
debug: false
|
|
73
|
+
}),
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/commands/build.ts
CHANGED
|
@@ -8,6 +8,9 @@ import prompts from 'prompts';
|
|
|
8
8
|
// Configs
|
|
9
9
|
import createCompilers from '../compiler';
|
|
10
10
|
|
|
11
|
+
// Core
|
|
12
|
+
import App from '../app';
|
|
13
|
+
|
|
11
14
|
/*----------------------------------
|
|
12
15
|
- TYPES
|
|
13
16
|
----------------------------------*/
|
|
@@ -17,7 +20,9 @@ import createCompilers from '../compiler';
|
|
|
17
20
|
----------------------------------*/
|
|
18
21
|
export const run = (): Promise<void> => new Promise(async (resolve) => {
|
|
19
22
|
|
|
20
|
-
const
|
|
23
|
+
const app = new App();
|
|
24
|
+
|
|
25
|
+
const multiCompiler = await createCompilers(app, 'prod');
|
|
21
26
|
|
|
22
27
|
multiCompiler.run((error, stats) => {
|
|
23
28
|
|
|
@@ -38,11 +38,11 @@ export async function run() {
|
|
|
38
38
|
|
|
39
39
|
const { simulate } = cli.args;
|
|
40
40
|
|
|
41
|
-
const temp =
|
|
41
|
+
const temp = app.paths.root + '/.deployment';
|
|
42
42
|
fs.emptyDirSync(temp);
|
|
43
43
|
|
|
44
44
|
// Merge package.json: framework + app
|
|
45
|
-
const appPkg = fs.readJSONSync(
|
|
45
|
+
const appPkg = fs.readJSONSync(app.paths.root + '/package.json');
|
|
46
46
|
const corePkg = fs.readJSONSync(cli.paths.core.root + '/package.json');
|
|
47
47
|
fs.outputJSONSync(temp + '/package.json', {
|
|
48
48
|
...appPkg,
|
|
@@ -51,7 +51,7 @@ export async function run() {
|
|
|
51
51
|
}, { spaces: 4 });
|
|
52
52
|
|
|
53
53
|
// Copy config file
|
|
54
|
-
fs.copyFileSync(
|
|
54
|
+
fs.copyFileSync( app.paths.root + (simulate ? '/env.yaml' : '/env.server.yaml'), temp + '/env.yaml' );
|
|
55
55
|
|
|
56
56
|
// Compile & Run Docker
|
|
57
57
|
await cli.shell(`docker compose up --build`);
|
package/src/commands/dev.ts
CHANGED
|
@@ -7,18 +7,23 @@ import fs from 'fs-extra';
|
|
|
7
7
|
import { spawn, ChildProcess } from 'child_process';
|
|
8
8
|
|
|
9
9
|
// Cor elibs
|
|
10
|
+
import cli from '../';
|
|
10
11
|
import Keyboard from '../utils/keyboard';
|
|
11
12
|
|
|
12
13
|
// Configs
|
|
13
14
|
import createCompilers, { compiling } from '../compiler';
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
// Core
|
|
17
|
+
import App from '../app';
|
|
15
18
|
|
|
16
19
|
/*----------------------------------
|
|
17
20
|
- COMMANDE
|
|
18
21
|
----------------------------------*/
|
|
19
22
|
export const run = () => new Promise<void>(async () => {
|
|
23
|
+
|
|
24
|
+
const app = new App();
|
|
20
25
|
|
|
21
|
-
const multiCompiler = await createCompilers('dev', {
|
|
26
|
+
const multiCompiler = await createCompilers(app, 'dev', {
|
|
22
27
|
before: () => {
|
|
23
28
|
|
|
24
29
|
console.log('before');
|
|
@@ -31,9 +36,6 @@ export const run = () => new Promise<void>(async () => {
|
|
|
31
36
|
}
|
|
32
37
|
});
|
|
33
38
|
|
|
34
|
-
// Allow the dev servet to fetch the frameworg node modules
|
|
35
|
-
//fs.createSymlinkSync( cli.paths.core.cli + '/node_modules', cli.paths.app.bin + '/node_modules', 'dir' );
|
|
36
|
-
|
|
37
39
|
multiCompiler.watch({
|
|
38
40
|
|
|
39
41
|
// https://webpack.js.org/configuration/watch/#watchoptions
|
|
@@ -53,7 +55,7 @@ export const run = () => new Promise<void>(async () => {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
console.log("Watch callback. Reloading app ...");
|
|
56
|
-
startApp();
|
|
58
|
+
startApp(app);
|
|
57
59
|
|
|
58
60
|
});
|
|
59
61
|
|
|
@@ -63,7 +65,7 @@ export const run = () => new Promise<void>(async () => {
|
|
|
63
65
|
await Promise.all(Object.values(compiling));
|
|
64
66
|
|
|
65
67
|
console.log(`Reloading app ...`);
|
|
66
|
-
startApp();
|
|
68
|
+
startApp(app);
|
|
67
69
|
|
|
68
70
|
});
|
|
69
71
|
|
|
@@ -78,12 +80,12 @@ export const run = () => new Promise<void>(async () => {
|
|
|
78
80
|
----------------------------------*/
|
|
79
81
|
let cp: ChildProcess | undefined = undefined;
|
|
80
82
|
|
|
81
|
-
async function startApp() {
|
|
83
|
+
async function startApp(app: App) {
|
|
82
84
|
|
|
83
85
|
stopApp();
|
|
84
86
|
|
|
85
87
|
console.info(`Launching new server ...`);
|
|
86
|
-
cp = spawn('node', ['' +
|
|
88
|
+
cp = spawn('node', ['' + app.paths.bin + '/server.js', '--preserve-symlinks'], {
|
|
87
89
|
|
|
88
90
|
// sdin, sdout, sderr
|
|
89
91
|
stdio: ['inherit', 'inherit', 'inherit']
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import prompts from 'prompts';
|
|
9
|
+
import cmd from 'node-cmd';
|
|
10
|
+
import replaceOnce from 'replace-once';
|
|
11
|
+
|
|
12
|
+
// Cor elibs
|
|
13
|
+
import cli from '../';
|
|
14
|
+
|
|
15
|
+
// Configs
|
|
16
|
+
const filesToConfig = [
|
|
17
|
+
'package.json',
|
|
18
|
+
'identity.yaml'
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
/*----------------------------------
|
|
22
|
+
- COMMANDE
|
|
23
|
+
----------------------------------*/
|
|
24
|
+
export const run = () => new Promise<void>(async () => {
|
|
25
|
+
|
|
26
|
+
const config = await prompts([{
|
|
27
|
+
type: 'text', name: 'name',
|
|
28
|
+
message: 'Project name ?',
|
|
29
|
+
initial: "MyProject",
|
|
30
|
+
validate: value => /[a-z0-9\-\.]/i.test(value) || "Must only include alphanumeric characters, and - . "
|
|
31
|
+
},{
|
|
32
|
+
type: 'text', name: 'dirname',
|
|
33
|
+
message: 'Folder name ?',
|
|
34
|
+
initial: value => value.toLowerCase(),
|
|
35
|
+
validate: value => /[a-z0-9\-\.]/.test(value) || "Must only include lowercase alphanumeric characters, and - . "
|
|
36
|
+
},{
|
|
37
|
+
type: 'text', name: 'description',
|
|
38
|
+
message: 'Briefly describe your project to your mom:',
|
|
39
|
+
initial: "It will revolutionnize the world",
|
|
40
|
+
validate: value => /[a-z0-9\-\. ]/i.test(value) || "Must only include alphanumeric characters, and - . "
|
|
41
|
+
},{
|
|
42
|
+
type: 'toggle', name: 'microservice',
|
|
43
|
+
message: 'Separate API from the UI servers ?'
|
|
44
|
+
}]);
|
|
45
|
+
|
|
46
|
+
const placeholders = {
|
|
47
|
+
PROJECT_NAME: config.name,
|
|
48
|
+
PACKAGE_NAME: config.name.toLowerCase(),
|
|
49
|
+
PROJECT_DESCRIPTION: config.description
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const paths = {
|
|
53
|
+
skeleton: path.join( cli.paths.core.cli, 'skeleton'),
|
|
54
|
+
project: path.join( process.cwd(), config.dirname)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Copy skeleton to cwd/<project-name>
|
|
58
|
+
console.info("Creating project skeleton ...");
|
|
59
|
+
fs.copySync( paths.skeleton, paths.project );
|
|
60
|
+
|
|
61
|
+
// Replace placeholders
|
|
62
|
+
console.info("Configuring project ...");
|
|
63
|
+
for (const file of filesToConfig) {
|
|
64
|
+
console.log('- ' + file);
|
|
65
|
+
|
|
66
|
+
const filepath = path.join( paths.project, file )
|
|
67
|
+
const content = fs.readFileSync(filepath, 'utf-8');
|
|
68
|
+
|
|
69
|
+
const placeholders_keys = Object.keys(placeholders).map(k => '{{ ' + k + ' }}')
|
|
70
|
+
const values = Object.values(placeholders);
|
|
71
|
+
|
|
72
|
+
fs.writeFileSync(filepath,
|
|
73
|
+
replaceOnce(content, placeholders_keys, values)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Npm install
|
|
78
|
+
console.info("Installing packages ...");
|
|
79
|
+
cmd.runSync(`cd "${paths.project}" && npm i`);
|
|
80
|
+
|
|
81
|
+
// Run demo app
|
|
82
|
+
/*console.info("Run demo ...");
|
|
83
|
+
await cli.shell('5htp dev');*/
|
|
84
|
+
|
|
85
|
+
});
|
|
@@ -4,20 +4,22 @@ import fs from 'fs-extra';
|
|
|
4
4
|
|
|
5
5
|
// Libs
|
|
6
6
|
import cli from '../..';
|
|
7
|
-
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
// Type
|
|
9
|
+
import type App from '../../app';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export default async ( app: App ) => {
|
|
12
|
+
|
|
13
|
+
const dossierCache = app.paths.root + '/public/app';
|
|
12
14
|
|
|
13
15
|
if (!fs.existsSync(dossierCache)) {
|
|
14
16
|
|
|
15
17
|
console.info(`Generating identity assets ...`);
|
|
16
18
|
fs.emptyDirSync(dossierCache);
|
|
17
19
|
|
|
18
|
-
const identity =
|
|
20
|
+
const identity = app.identity;
|
|
19
21
|
|
|
20
|
-
const response = await favicons(
|
|
22
|
+
const response = await favicons( app.paths.root + '/src/client/assets/identity/logo.svg', {
|
|
21
23
|
|
|
22
24
|
path: '/assets/img/identite/favicons/',
|
|
23
25
|
appName: identity.name,
|
|
@@ -26,32 +26,35 @@ import createCommonConfig, { TCompileMode, regex } from '../common';
|
|
|
26
26
|
import identityAssets from './identite';
|
|
27
27
|
import cli from '../..';
|
|
28
28
|
|
|
29
|
+
// Type
|
|
30
|
+
import type App from '../../app';
|
|
31
|
+
|
|
29
32
|
/*----------------------------------
|
|
30
33
|
- CONFIG
|
|
31
34
|
----------------------------------*/
|
|
32
|
-
export default function createCompiler(mode: TCompileMode): webpack.Configuration {
|
|
35
|
+
export default function createCompiler( app: App, mode: TCompileMode ): webpack.Configuration {
|
|
33
36
|
|
|
34
37
|
console.info(`Creating compiler for client (${mode}).`);
|
|
35
38
|
const dev = mode === 'dev';
|
|
36
39
|
|
|
37
|
-
const commonConfig = createCommonConfig('client', mode);
|
|
40
|
+
const commonConfig = createCommonConfig(app, 'client', mode);
|
|
38
41
|
|
|
39
42
|
// Pas besoin d'attendre que les assets soient générés pour lancer la compilation
|
|
40
|
-
identityAssets();
|
|
43
|
+
identityAssets(app);
|
|
41
44
|
|
|
42
45
|
// Symlinks to public
|
|
43
|
-
/*const publicDirs = fs.readdirSync(
|
|
46
|
+
/*const publicDirs = fs.readdirSync(app.paths.root + '/public');
|
|
44
47
|
for (const publicDir of publicDirs)
|
|
45
48
|
fs.symlinkSync(
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
app.paths.root + '/public/' + publicDir,
|
|
50
|
+
app.paths.public + '/' + publicDir
|
|
48
51
|
);*/
|
|
49
52
|
|
|
50
53
|
// Convert tsconfig cli.paths to webpack aliases
|
|
51
|
-
const { aliases } =
|
|
54
|
+
const { aliases } = app.aliases.client.forWebpack(app.paths.root + '/node_modules');
|
|
52
55
|
// Disable access to server-side libs from client side
|
|
53
56
|
delete aliases["@server"];
|
|
54
|
-
delete aliases["@/server"];
|
|
57
|
+
delete aliases["@/server"];
|
|
55
58
|
|
|
56
59
|
const config: webpack.Configuration = {
|
|
57
60
|
|
|
@@ -73,7 +76,7 @@ export default function createCompiler(mode: TCompileMode): webpack.Configuratio
|
|
|
73
76
|
output: {
|
|
74
77
|
|
|
75
78
|
pathinfo: dev,
|
|
76
|
-
path:
|
|
79
|
+
path: app.paths.bin + '/public',
|
|
77
80
|
filename: '[name].js', // Output client.js
|
|
78
81
|
assetModuleFilename: '[hash][ext]',
|
|
79
82
|
|
|
@@ -101,21 +104,21 @@ export default function createCompiler(mode: TCompileMode): webpack.Configuratio
|
|
|
101
104
|
test: regex.scripts,
|
|
102
105
|
include: [
|
|
103
106
|
|
|
104
|
-
|
|
107
|
+
app.paths.root + '/src/client',
|
|
105
108
|
cli.paths.core.root + '/src/client',
|
|
106
109
|
|
|
107
|
-
|
|
110
|
+
app.paths.root + '/src/common',
|
|
108
111
|
cli.paths.core.root + '/src/common',
|
|
109
112
|
|
|
110
113
|
],
|
|
111
|
-
rules: require('../common/babel')('client', dev)
|
|
114
|
+
rules: require('../common/babel')(app, 'client', dev)
|
|
112
115
|
},
|
|
113
116
|
|
|
114
117
|
// Les pages étan tà la fois compilées dans le bundle client et serveur
|
|
115
118
|
// On ne compile les ressources (css) qu'une seule fois
|
|
116
119
|
{
|
|
117
120
|
test: regex.style,
|
|
118
|
-
rules: require('../common/files/style')(true, dev),
|
|
121
|
+
rules: require('../common/files/style')(app, true, dev),
|
|
119
122
|
|
|
120
123
|
// Don't consider CSS imports dead code even if the
|
|
121
124
|
// containing package claims to have no side effects.
|
|
@@ -124,14 +127,14 @@ export default function createCompiler(mode: TCompileMode): webpack.Configuratio
|
|
|
124
127
|
sideEffects: true,
|
|
125
128
|
},
|
|
126
129
|
|
|
127
|
-
...require('../common/files/images')(dev, true),
|
|
130
|
+
...require('../common/files/images')(app, dev, true),
|
|
128
131
|
|
|
129
|
-
...require('../common/files/autres')(dev, true),
|
|
132
|
+
...require('../common/files/autres')(app, dev, true),
|
|
130
133
|
|
|
131
134
|
// Exclude dev modules from production build
|
|
132
135
|
/*...(dev ? [] : [
|
|
133
136
|
{
|
|
134
|
-
test:
|
|
137
|
+
test: app.paths.root + '/node_modules/react-deep-force-update/lib/index.js'),
|
|
135
138
|
loader: 'null-loader',
|
|
136
139
|
},
|
|
137
140
|
]),*/
|
|
@@ -149,7 +152,7 @@ export default function createCompiler(mode: TCompileMode): webpack.Configuratio
|
|
|
149
152
|
// Emit a file with assets cli.paths
|
|
150
153
|
// https://github.com/webdeveric/webpack-assets-manifest#options
|
|
151
154
|
new WebpackAssetsManifest({
|
|
152
|
-
output:
|
|
155
|
+
output: app.paths.root + `/bin/asset-manifest.json`,
|
|
153
156
|
publicPath: true,
|
|
154
157
|
writeToDisk: true, // Force la copie du fichier sur e disque, au lieu d'en mémoire en mode dev
|
|
155
158
|
customize: ({ key, value }) => {
|
|
@@ -159,7 +162,7 @@ export default function createCompiler(mode: TCompileMode): webpack.Configuratio
|
|
|
159
162
|
},
|
|
160
163
|
done: (manifest, stats) => {
|
|
161
164
|
// Write chunk-manifest.json.json
|
|
162
|
-
const chunkFileName =
|
|
165
|
+
const chunkFileName = app.paths.root + `/bin/chunk-manifest.json`;
|
|
163
166
|
try {
|
|
164
167
|
const fileFilter = file => !file.endsWith('.map');
|
|
165
168
|
const addPath = file => manifest.getPublicPath(file);
|