@fmsim/builder 0.0.49
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/CHANGELOG.md +8 -0
- package/README.md +0 -0
- package/controller/entries-builder.js +43 -0
- package/docker/nginx/Dockerfile +15 -0
- package/docker/nginx/app.conf +19 -0
- package/docker/nginx/nginx.conf +47 -0
- package/docker/nginx/operato-nginx-create.sh +13 -0
- package/docker/operato-env/Dockerfile +47 -0
- package/docker/operato-env/operato-env-create.sh +18 -0
- package/index.js +0 -0
- package/package.json +76 -0
- package/web-loaders/things-factory-module-loader.js +56 -0
- package/web-loaders/things-scene-config-webpack-loader.js +18 -0
- package/web-loaders/things-scene-webpack-loader.js +12 -0
- package/webpack-plugins/folder-override-plugin.js +112 -0
- package/webpack-plugins/i18n-bundler-plugin.js +100 -0
- package/webpack-plugins/theme-override-plugin.js +56 -0
- package/webpack.config.dev.js +268 -0
- package/webpack.config.js +265 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
6
|
+
and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
<!-- ## [Unreleased] -->
|
package/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 모든 클라이언트 모듈의 entries 파일들에 오버라이드를 적용해서 최종에 entries 파일로 병합될 파일리스트를 선정하는 기능.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const glob = require('glob')
|
|
7
|
+
|
|
8
|
+
module.exports = function () {
|
|
9
|
+
const { orderedModuleNames, appRootPath } = require('@things-factory/env')
|
|
10
|
+
|
|
11
|
+
const AppPackage = require(path.resolve(appRootPath, 'package.json'))
|
|
12
|
+
|
|
13
|
+
var appname = AppPackage.name
|
|
14
|
+
|
|
15
|
+
var reversedModuleNames = [...orderedModuleNames, appname].reverse()
|
|
16
|
+
var entryFiles = {}
|
|
17
|
+
|
|
18
|
+
/* 최상위 모듈부터 복사한다. 하위 모듈에서는 중복 여부에 따라 복사여부를 결정한다. */
|
|
19
|
+
reversedModuleNames.forEach(m => {
|
|
20
|
+
var modulePackage = appname === m ? AppPackage : require(`${m}/package.json`)
|
|
21
|
+
var browserPath = modulePackage.browser
|
|
22
|
+
|
|
23
|
+
if (!browserPath) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var modulePath = appname === m ? appRootPath : path.dirname(require.resolve(`${m}/package.json`))
|
|
28
|
+
modulePath = path.dirname(path.join(modulePath, browserPath))
|
|
29
|
+
|
|
30
|
+
var files = glob.sync(`${path.join(modulePath, 'entries', '**', '*.js')}`)
|
|
31
|
+
var idx = path.join(modulePath, 'entries').length
|
|
32
|
+
|
|
33
|
+
files.forEach(filepath => {
|
|
34
|
+
let filename = filepath.substring(idx + 1, filepath.length - 3)
|
|
35
|
+
|
|
36
|
+
if (!entryFiles[filename]) {
|
|
37
|
+
entryFiles[filename] = [filepath]
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return entryFiles
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FROM nginx
|
|
2
|
+
|
|
3
|
+
# 기본 설정 파일을 지우고, 새로운 파일로 대체합니다.
|
|
4
|
+
RUN rm -rf /etc/nginx/conf.d/default.conf
|
|
5
|
+
|
|
6
|
+
COPY ./app.conf /etc/nginx/conf.d/app.conf
|
|
7
|
+
COPY ./nginx.conf /etc/nginx/nginx.conf
|
|
8
|
+
|
|
9
|
+
VOLUME ["/data", "/etc/nginx", "/var/log/nginx"]
|
|
10
|
+
|
|
11
|
+
WORKDIR /etc/nginx
|
|
12
|
+
|
|
13
|
+
CMD ["nginx"]
|
|
14
|
+
|
|
15
|
+
EXPOSE 80
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
server {
|
|
2
|
+
listen 80;
|
|
3
|
+
listen [::]:80;
|
|
4
|
+
|
|
5
|
+
server_name "";
|
|
6
|
+
|
|
7
|
+
access_log off;
|
|
8
|
+
|
|
9
|
+
location / {
|
|
10
|
+
proxy_pass http://app:3000;
|
|
11
|
+
proxy_set_header Host $host:$server_port;
|
|
12
|
+
proxy_set_header X-Forwarded-Host $server_name;
|
|
13
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
14
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
15
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
16
|
+
proxy_set_header Connection "upgrade";
|
|
17
|
+
proxy_http_version 1.1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#nginx.conf
|
|
2
|
+
daemon off;
|
|
3
|
+
user www-data;
|
|
4
|
+
worker_processes 2;
|
|
5
|
+
|
|
6
|
+
error_log /var/log/nginx/error.log warn;
|
|
7
|
+
pid /var/run/nginx.pid;
|
|
8
|
+
|
|
9
|
+
events {
|
|
10
|
+
worker_connections 1024;
|
|
11
|
+
use epoll;
|
|
12
|
+
accept_mutex off;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
http {
|
|
16
|
+
include /etc/nginx/mime.types;
|
|
17
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
18
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
19
|
+
|
|
20
|
+
default_type application/octet-stream;
|
|
21
|
+
|
|
22
|
+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
|
23
|
+
'$status $body_bytes_sent "$http_referer" '
|
|
24
|
+
'"$http_user_agent" "$http_x_forwarded_for"';
|
|
25
|
+
|
|
26
|
+
access_log /var/log/nginx/access.log main;
|
|
27
|
+
|
|
28
|
+
sendfile on;
|
|
29
|
+
#tcp_nopush on;
|
|
30
|
+
|
|
31
|
+
keepalive_timeout 65;
|
|
32
|
+
|
|
33
|
+
client_max_body_size 300m;
|
|
34
|
+
client_body_buffer_size 128k;
|
|
35
|
+
|
|
36
|
+
gzip on;
|
|
37
|
+
gzip_http_version 1.0;
|
|
38
|
+
gzip_comp_level 6;
|
|
39
|
+
gzip_min_length 0;
|
|
40
|
+
gzip_buffers 16 8k;
|
|
41
|
+
gzip_proxied any;
|
|
42
|
+
gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;
|
|
43
|
+
gzip_disable "MSIE [1-6]\.";
|
|
44
|
+
gzip_vary on;
|
|
45
|
+
|
|
46
|
+
include /etc/nginx/conf.d/*.conf;
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
VERSION=latest
|
|
4
|
+
|
|
5
|
+
if [ $# -eq 0 ] ; then
|
|
6
|
+
echo "Default Version latest"
|
|
7
|
+
else
|
|
8
|
+
VERSION=$1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
echo "VERSION : ${VERSION}"
|
|
12
|
+
|
|
13
|
+
docker image build -t hatiolab/operato-nginx:${VERSION} -f Dockerfile --platform ${PLATFORM} .
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Use an official node image
|
|
2
|
+
FROM node:18.12
|
|
3
|
+
|
|
4
|
+
ARG DEBIAN_FRONTEND=noninteractive
|
|
5
|
+
|
|
6
|
+
# Install the required packages
|
|
7
|
+
|
|
8
|
+
RUN echo "deb http://ftp.de.debian.org/debian stable main" > /etc/apt/sources.list
|
|
9
|
+
|
|
10
|
+
RUN apt-get update
|
|
11
|
+
|
|
12
|
+
RUN apt-get install -y --no-install-recommends apt-utils
|
|
13
|
+
RUN apt-get install -y chromium
|
|
14
|
+
RUN apt-get install -y libcups2-dev
|
|
15
|
+
RUN apt-get install -y libavahi-compat-libdnssd-dev
|
|
16
|
+
RUN apt-get install -y gconf-service libasound2 libatk1.0-0 libcairo2 libcups2 libfontconfig1 libgdk-pixbuf2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libxss1 fonts-liberation libnss3 lsb-release xdg-utils libaio1
|
|
17
|
+
|
|
18
|
+
RUN apt update
|
|
19
|
+
RUN apt-get install -y ghostscript
|
|
20
|
+
RUN apt-get install -y curl
|
|
21
|
+
RUN apt-get install -y git
|
|
22
|
+
|
|
23
|
+
# install chrome
|
|
24
|
+
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
|
25
|
+
RUN dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install
|
|
26
|
+
RUN rm google-chrome-stable_current_amd64.deb
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# make oracle path
|
|
31
|
+
RUN mkdir -p /opt/oracle
|
|
32
|
+
WORKDIR /opt/oracle
|
|
33
|
+
|
|
34
|
+
# download newest oracle cilent for connect to Oracle Database
|
|
35
|
+
RUN wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip && \
|
|
36
|
+
unzip instantclient-basiclite-linuxx64.zip && \
|
|
37
|
+
rm -f instantclient-basiclite-linuxx64.zip && \
|
|
38
|
+
cd /opt/oracle/instantclient* && \
|
|
39
|
+
rm -f *jdbc* *occi* *mysql* *mql1* *ipc1* *jar uidrvci genezi adrci && \
|
|
40
|
+
echo /opt/oracle/instantclient* > /etc/ld.so.conf.d/oracle-instantclient.conf &&\
|
|
41
|
+
ldconfig
|
|
42
|
+
|
|
43
|
+
# fix the font issue of headless control
|
|
44
|
+
RUN apt-get update && apt-get install -y fonts-unfonts-core
|
|
45
|
+
|
|
46
|
+
RUN apt-get clean \
|
|
47
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
IMAGE_LASTEST=latest
|
|
4
|
+
PLATFORM=linux/amd64
|
|
5
|
+
VERSION=18
|
|
6
|
+
|
|
7
|
+
if [ $# -eq 0 ] ; then
|
|
8
|
+
echo "Default Version ${VERSION}"
|
|
9
|
+
echo "Default Platform ${PLATFORM}"
|
|
10
|
+
else
|
|
11
|
+
VERSION=$1
|
|
12
|
+
IMAGE_LASTEST=$2
|
|
13
|
+
PLATFORM=$3
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
docker image build -t hatiolab/operato-env:${VERSION} -t hatiolab/operato-env:${IMAGE_LASTEST} -f Dockerfile --platform ${PLATFORM} .
|
|
17
|
+
|
|
18
|
+
docker image push hatiolab/operato-env:${VERSION} && docker image push hatiolab/operato-env:${IMAGE_LASTEST}
|
package/index.js
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fmsim/builder",
|
|
3
|
+
"version": "0.0.49",
|
|
4
|
+
"description": "Layout View 어플리케이션 빌드를 위해 구성된 모듈입니다.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"author": "Hearty Oh <heartyoh@hatiolab.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"@things-factory:registry": "https://registry.npmjs.org"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/hatiolab/fmsim.git",
|
|
15
|
+
"directory": "packages/integrator"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@babel/cli": "^7.18.10",
|
|
19
|
+
"@babel/core": "^7.18.13",
|
|
20
|
+
"@babel/eslint-parser": "^7.18.9",
|
|
21
|
+
"@babel/plugin-proposal-decorators": "^7.18.10",
|
|
22
|
+
"@babel/preset-env": "^7.18.10",
|
|
23
|
+
"@babel/preset-react": "^7.18.6",
|
|
24
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
25
|
+
"@babel/register": "^7.18.9",
|
|
26
|
+
"@types/jest": "^29.2.1",
|
|
27
|
+
"@types/lodash": "^4.14.139",
|
|
28
|
+
"@types/node": "^18.11.18",
|
|
29
|
+
"@types/react": "^18.0.26",
|
|
30
|
+
"@types/react-dom": "^18.0.11",
|
|
31
|
+
"babel-jest": "^29.2.2",
|
|
32
|
+
"babel-loader": "^9.1.2",
|
|
33
|
+
"concurrently": "^8.0.1",
|
|
34
|
+
"copy-webpack-plugin": "^11.0.0",
|
|
35
|
+
"copyfiles": "^2.4.1",
|
|
36
|
+
"cross-fetch": "^3.0.4",
|
|
37
|
+
"css-loader": "^6.7.3",
|
|
38
|
+
"docdash": "^2.0.1",
|
|
39
|
+
"documentation": "^14.0.0",
|
|
40
|
+
"element-closest": "^3.0.2",
|
|
41
|
+
"eslint": "^8.39.0",
|
|
42
|
+
"faker": "^6.6.6",
|
|
43
|
+
"file-loader": "^6.2.0",
|
|
44
|
+
"fs-extra": "^11.1.1",
|
|
45
|
+
"full-icu": "^1.3.0",
|
|
46
|
+
"get-port": "^6.1.2",
|
|
47
|
+
"graphql": "^16.5.0",
|
|
48
|
+
"html-webpack-plugin": "^5.5.0",
|
|
49
|
+
"intl-pluralrules": "^2.0.0",
|
|
50
|
+
"jest": "^29.2.2",
|
|
51
|
+
"lerna": "^6.6.1",
|
|
52
|
+
"less": "^4.1.3",
|
|
53
|
+
"less-loader": "^11.1.0",
|
|
54
|
+
"mini-css-extract-plugin": "^2.5.2",
|
|
55
|
+
"node-polyfill-webpack-plugin": "^2.0.1",
|
|
56
|
+
"plop": "^3.1.1",
|
|
57
|
+
"postcss-loader": "^7.3.0",
|
|
58
|
+
"prettier": "^2.5.1",
|
|
59
|
+
"raw-loader": "^4.0.2",
|
|
60
|
+
"replace-in-file-webpack-plugin": "^1.0.6",
|
|
61
|
+
"rimraf": "^5.0.0",
|
|
62
|
+
"saddle-up": "^0.5.1",
|
|
63
|
+
"sass-loader": "^13.2.2",
|
|
64
|
+
"terser": "^5.1.0",
|
|
65
|
+
"text-loader": "^0.0.1",
|
|
66
|
+
"ts-jest": "^29.1.0",
|
|
67
|
+
"ts-node": "^10.9.1",
|
|
68
|
+
"tsconfig-paths": "^4.1.0",
|
|
69
|
+
"typescript": "^5.0.4",
|
|
70
|
+
"webpack": "^5.65.0",
|
|
71
|
+
"webpack-cli": "^5.0.1",
|
|
72
|
+
"webpack-dev-server": "^4.11.0",
|
|
73
|
+
"workbox-webpack-plugin": "^6.5.4"
|
|
74
|
+
},
|
|
75
|
+
"gitHead": "59b7cd248a3b0e637d4e124a28829441c4b258b2"
|
|
76
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const debug = require('debug')('things-factory:builder:things-factory-module-loader')
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const { orderedModuleNames } = require('@things-factory/env')
|
|
5
|
+
|
|
6
|
+
const appRootPath = path.resolve('.')
|
|
7
|
+
const selfModulePackage = require(path.resolve(appRootPath, 'package.json'))
|
|
8
|
+
const selfModuleName = selfModulePackage.name
|
|
9
|
+
|
|
10
|
+
function pkgLoader(moduleName) {
|
|
11
|
+
try {
|
|
12
|
+
if (selfModuleName == moduleName) {
|
|
13
|
+
return selfModulePackage
|
|
14
|
+
} else {
|
|
15
|
+
return require(moduleName)
|
|
16
|
+
}
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.error('load error', e)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = function (content) {
|
|
23
|
+
debug('Module Configuration Begin')
|
|
24
|
+
|
|
25
|
+
const moduleConfigMap = orderedModuleNames.reduce((sum, name) => {
|
|
26
|
+
const pkg = pkgLoader(name + '/package.json')
|
|
27
|
+
const thingsFactoryConfig = pkg.thingsFactoryConfig ?? 'things-factory.config.js'
|
|
28
|
+
const config = `${name}/${thingsFactoryConfig}`
|
|
29
|
+
|
|
30
|
+
sum[name] = { pkg, config }
|
|
31
|
+
return sum
|
|
32
|
+
}, {})
|
|
33
|
+
|
|
34
|
+
var result = `
|
|
35
|
+
export var modules = [];
|
|
36
|
+
|
|
37
|
+
${orderedModuleNames
|
|
38
|
+
.filter(name => moduleConfigMap[name])
|
|
39
|
+
.map((module, idx) => {
|
|
40
|
+
return `
|
|
41
|
+
import v${idx} from "${moduleConfigMap[module].config}"
|
|
42
|
+
modules.push({
|
|
43
|
+
...v${idx},
|
|
44
|
+
name: "${moduleConfigMap[module].pkg.name}",
|
|
45
|
+
version: "${moduleConfigMap[module].pkg.version}",
|
|
46
|
+
license: "${moduleConfigMap[module].pkg.license}"
|
|
47
|
+
})
|
|
48
|
+
`
|
|
49
|
+
})
|
|
50
|
+
.join('')}
|
|
51
|
+
`
|
|
52
|
+
|
|
53
|
+
debug('Module Configuration End.')
|
|
54
|
+
|
|
55
|
+
return result
|
|
56
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const debug = require('debug')('things-factory:builder:things-scene-config-webpack-loader')
|
|
2
|
+
|
|
3
|
+
const { sceneModuleNames } = require('@things-factory/env')
|
|
4
|
+
|
|
5
|
+
module.exports = function (content) {
|
|
6
|
+
const script =
|
|
7
|
+
'var metas = []\n' +
|
|
8
|
+
sceneModuleNames
|
|
9
|
+
.map((name, idx) => {
|
|
10
|
+
return `import v${idx} from "${name}/things-scene.config.js"\nmetas[${idx}] = v${idx}`
|
|
11
|
+
})
|
|
12
|
+
.join('\n') +
|
|
13
|
+
'\nexport default metas\n'
|
|
14
|
+
|
|
15
|
+
debug('Things Scene Components for Modeller\n', script)
|
|
16
|
+
|
|
17
|
+
return script
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const debug = require('debug')('things-factory:builder:things-scene-webpack-loader')
|
|
2
|
+
|
|
3
|
+
const { sceneModuleNames } = require('@things-factory/env')
|
|
4
|
+
|
|
5
|
+
module.exports = function (content) {
|
|
6
|
+
|
|
7
|
+
const script = sceneModuleNames.map(component => `import '${component}'\n`).join('')
|
|
8
|
+
|
|
9
|
+
debug('Things Scene Components', '\n' + script)
|
|
10
|
+
|
|
11
|
+
return script
|
|
12
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 모든 모듈의 특정 폴더(특히, assets)를 모듈 디펜던시 순서에 따라 오버라이드 및 병합한다.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const fs = require('fs-extra')
|
|
7
|
+
const glob = require('glob')
|
|
8
|
+
const loaderUtils = require('loader-utils')
|
|
9
|
+
const debug = require('debug')('things-factory:builder:folder-override-plugin')
|
|
10
|
+
|
|
11
|
+
const { orderedModuleNames, sceneModuleNames, appRootPath } = require('@things-factory/env')
|
|
12
|
+
|
|
13
|
+
const AppPackage = require(path.resolve(appRootPath, 'package.json'))
|
|
14
|
+
|
|
15
|
+
class FolderOverridePlugin {
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.options = options
|
|
18
|
+
this.writtenFrom = {}
|
|
19
|
+
this.writtenTo = {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
apply(compiler) {
|
|
23
|
+
var contexts = []
|
|
24
|
+
|
|
25
|
+
compiler.hooks.thisCompilation.tap({ name: 'FolderOverridePlugin' }, compilation => {
|
|
26
|
+
/* contexts 초기화 */
|
|
27
|
+
contexts = []
|
|
28
|
+
var { target: targetDir } = this.options
|
|
29
|
+
|
|
30
|
+
var appname = AppPackage.name
|
|
31
|
+
var modules = [...orderedModuleNames, ...sceneModuleNames].filter(modulename => modulename !== appname)
|
|
32
|
+
modules.push(appname)
|
|
33
|
+
var reversedModuleNames = modules.reverse()
|
|
34
|
+
|
|
35
|
+
/* 최상위 모듈부터 복사한다. 하위 모듈에서는 중복 여부에 따라 복사여부를 결정한다. */
|
|
36
|
+
reversedModuleNames.forEach(m => {
|
|
37
|
+
if (appname == m) {
|
|
38
|
+
var modulePath = appRootPath
|
|
39
|
+
} else {
|
|
40
|
+
var modulePath = path.dirname(require.resolve(`${m}/package.json`))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var sourcePath = path.resolve(modulePath, targetDir)
|
|
44
|
+
contexts.push(sourcePath)
|
|
45
|
+
|
|
46
|
+
var files = glob.sync(`${sourcePath}/**/*`)
|
|
47
|
+
|
|
48
|
+
files.forEach(filepath => {
|
|
49
|
+
let relativePath = path.relative(modulePath, filepath)
|
|
50
|
+
|
|
51
|
+
this.write(compilation, filepath, relativePath)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
compiler.hooks.afterEmit.tap({ name: 'FolderOverridePlugin' }, compilation => {
|
|
57
|
+
// Add context dependencies if they're not already tracked
|
|
58
|
+
contexts.forEach(context => {
|
|
59
|
+
if (!compilation.contextDependencies.has(context)) {
|
|
60
|
+
compilation.contextDependencies.add(context)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
write(compilation, filepath, relativePath) {
|
|
67
|
+
var stat = fs.statSync(filepath)
|
|
68
|
+
if (stat.isDirectory()) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
var content = fs.readFileSync(filepath)
|
|
73
|
+
const hash = loaderUtils.getHashDigest(content)
|
|
74
|
+
const webpackTo = loaderUtils.interpolateName(
|
|
75
|
+
{
|
|
76
|
+
resourcePath: filepath
|
|
77
|
+
},
|
|
78
|
+
relativePath,
|
|
79
|
+
{
|
|
80
|
+
content
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if (this.writtenTo[webpackTo] && this.writtenTo[webpackTo] !== filepath) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.writtenFrom[filepath] && this.writtenFrom[filepath][hash]) {
|
|
89
|
+
// debug(`skipping '${filepath}', because it hasn't changed`)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// debug(`writing '${webpackTo}' from '${filepath}'`)
|
|
94
|
+
this.writtenTo[webpackTo] = filepath
|
|
95
|
+
this.writtenFrom[filepath] = {
|
|
96
|
+
[hash]: true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.writtenFrom[filepath].webpackTo = webpackTo
|
|
100
|
+
|
|
101
|
+
compilation.assets[webpackTo] = {
|
|
102
|
+
size() {
|
|
103
|
+
return stat.size
|
|
104
|
+
},
|
|
105
|
+
source() {
|
|
106
|
+
return content
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = FolderOverridePlugin
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 모든 모듈의 translations에 정의된 locale 리소스들을 모두 모아서 하나의 translations로 병합한다.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs-extra')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const glob = require('glob')
|
|
8
|
+
const debug = require('debug')('things-factory:builder:i18n-bundler-plugin')
|
|
9
|
+
|
|
10
|
+
const { orderedModuleNames, sceneModuleNames, appRootPath } = require('@things-factory/env')
|
|
11
|
+
|
|
12
|
+
const AppPackage = require(path.resolve(appRootPath, 'package.json'))
|
|
13
|
+
|
|
14
|
+
function merge(target, source) {
|
|
15
|
+
for (let key of Object.keys(source)) {
|
|
16
|
+
if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key]))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Object.assign(target || {}, source)
|
|
20
|
+
return target
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class I18nBundlerPlugin {
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
this.options = options
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
apply(compiler) {
|
|
29
|
+
var contexts = []
|
|
30
|
+
var files = []
|
|
31
|
+
|
|
32
|
+
compiler.hooks.thisCompilation.tap({ name: 'I18nBundlerPlugin' }, compilation => {
|
|
33
|
+
/* dependencies 초기화 */
|
|
34
|
+
contexts = []
|
|
35
|
+
files = []
|
|
36
|
+
|
|
37
|
+
var appname = AppPackage.name
|
|
38
|
+
var modules = [...orderedModuleNames, ...sceneModuleNames].filter(modulename => modulename !== appname)
|
|
39
|
+
modules.push(appname)
|
|
40
|
+
|
|
41
|
+
var translationsDir = this.options.output || 'translations'
|
|
42
|
+
|
|
43
|
+
var translations = modules.reduce((summary, m) => {
|
|
44
|
+
if (appname == m) {
|
|
45
|
+
var modulePath = appRootPath
|
|
46
|
+
} else {
|
|
47
|
+
var modulePath = path.dirname(require.resolve(`${m}/package.json`))
|
|
48
|
+
}
|
|
49
|
+
var translationsPath = path.resolve(modulePath, translationsDir)
|
|
50
|
+
contexts.push(translationsPath)
|
|
51
|
+
|
|
52
|
+
files = glob.sync(`${translationsPath}/*.json`)
|
|
53
|
+
|
|
54
|
+
return files.reduce((summary, file) => {
|
|
55
|
+
try {
|
|
56
|
+
var contents = fs.readFileSync(file)
|
|
57
|
+
var json = JSON.parse(contents)
|
|
58
|
+
|
|
59
|
+
var filename = file.replace(/^.*[\\\/]/, '')
|
|
60
|
+
var locale = filename.substring(0, filename.length - 5)
|
|
61
|
+
|
|
62
|
+
summary[locale] = merge(summary[locale] || {}, json)
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error(e)
|
|
65
|
+
} finally {
|
|
66
|
+
return summary
|
|
67
|
+
}
|
|
68
|
+
}, summary)
|
|
69
|
+
}, {})
|
|
70
|
+
|
|
71
|
+
/* 각 locale 별로 file을 저장한다. */
|
|
72
|
+
for (let locale in translations) {
|
|
73
|
+
let localePath = path.join(translationsDir, `${locale}.json`)
|
|
74
|
+
let content = JSON.stringify(translations[locale], null, 2)
|
|
75
|
+
|
|
76
|
+
// debug(`Restoring locale '${locale}' resource into '${localePath}'`)
|
|
77
|
+
|
|
78
|
+
compilation.assets[localePath] = {
|
|
79
|
+
source: function () {
|
|
80
|
+
return content
|
|
81
|
+
},
|
|
82
|
+
size: function () {
|
|
83
|
+
return content.length
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
compiler.hooks.afterEmit.tap({ name: 'I18nBundlerPlugin' }, compilation => {
|
|
90
|
+
// Add context dependencies if they're not already tracked
|
|
91
|
+
contexts.forEach(context => {
|
|
92
|
+
if (!compilation.contextDependencies.has(context)) {
|
|
93
|
+
compilation.contextDependencies.add(context)
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = I18nBundlerPlugin
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 모든 모듈의 theme 파일들에 오버라이드를 적용해서 최종에 theme css파일로 병합될 파일리스트를 선정하여, webpack의 inputOption에 추가한다.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const glob = require('glob')
|
|
7
|
+
|
|
8
|
+
const { orderedModuleNames, appRootPath } = require('@things-factory/env')
|
|
9
|
+
|
|
10
|
+
const AppPackage = require(`${appRootPath}/package.json`)
|
|
11
|
+
|
|
12
|
+
class ThemeOverridePlugin {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.options = options
|
|
15
|
+
this.writtenFrom = {}
|
|
16
|
+
this.writtenTo = {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
apply(compiler) {
|
|
20
|
+
compiler.hooks.entryOption.tap({ name: 'ThemeOverridePlugin' }, (context, entry) => {
|
|
21
|
+
var appname = AppPackage.name
|
|
22
|
+
|
|
23
|
+
var { chunk = 'theme', themeFolder = path.join('client', 'themes') } = this.options
|
|
24
|
+
|
|
25
|
+
var reversedModuleNames = [...orderedModuleNames, appname].reverse()
|
|
26
|
+
var themeFiles = {}
|
|
27
|
+
|
|
28
|
+
/* 최상위 모듈부터 복사한다. 하위 모듈에서는 중복 여부에 따라 복사여부를 결정한다. */
|
|
29
|
+
reversedModuleNames.forEach(m => {
|
|
30
|
+
if (appname == m) {
|
|
31
|
+
var modulePath = appRootPath
|
|
32
|
+
} else {
|
|
33
|
+
var modulePath = path.dirname(require.resolve(`${m}/package.json`))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var sourcePath = path.join(modulePath, themeFolder)
|
|
37
|
+
|
|
38
|
+
var files = glob.sync(path.join(sourcePath, '*.?(sass|scss|css)'))
|
|
39
|
+
|
|
40
|
+
files.forEach(filepath => {
|
|
41
|
+
let filename = path.basename(filepath)
|
|
42
|
+
|
|
43
|
+
if (!themeFiles[filename]) {
|
|
44
|
+
themeFiles[filename] = filepath
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
entry[chunk] = {
|
|
50
|
+
import: Object.values(themeFiles)
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = ThemeOverridePlugin
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const webpack = require('webpack')
|
|
4
|
+
const HTMLWebpackPlugin = require('html-webpack-plugin')
|
|
5
|
+
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
|
6
|
+
const I18nBundlerPlugin = require('./webpack-plugins/i18n-bundler-plugin')
|
|
7
|
+
const FolderOverridePlugin = require('./webpack-plugins/folder-override-plugin')
|
|
8
|
+
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
|
|
9
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
10
|
+
const ThemeOverridePlugin = require('./webpack-plugins/theme-override-plugin')
|
|
11
|
+
const EntryBuilder = require('./controller/entries-builder')
|
|
12
|
+
|
|
13
|
+
const glob = require('glob')
|
|
14
|
+
const debug = require('debug')('things-factory:builder:webpack.config.dev')
|
|
15
|
+
|
|
16
|
+
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
|
|
17
|
+
|
|
18
|
+
const { appRootPath } = require('@things-factory/env')
|
|
19
|
+
const AppPackage = require(path.resolve(appRootPath, 'package.json'))
|
|
20
|
+
|
|
21
|
+
const OUTPUT_PATH = path.resolve(appRootPath, 'dist-app')
|
|
22
|
+
|
|
23
|
+
debug('Output Path: ', OUTPUT_PATH)
|
|
24
|
+
|
|
25
|
+
const module_resolve = require('resolve')
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
let pathName = module_resolve.sync('@things-factory/shell', {
|
|
29
|
+
basedir: process.cwd()
|
|
30
|
+
})
|
|
31
|
+
var ShellModulePath = path.resolve(pathName, '../..')
|
|
32
|
+
var NodeModulePath = path.resolve(pathName, '../../../..')
|
|
33
|
+
var NodeModuleParentPath = path.resolve(NodeModulePath, '..')
|
|
34
|
+
} catch (e) {
|
|
35
|
+
throw new Error('@things-factory/shell module not found.', e)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
var BuilderModulePath = path.resolve(
|
|
40
|
+
module_resolve.sync('@things-factory/builder', {
|
|
41
|
+
basedir: process.cwd()
|
|
42
|
+
}),
|
|
43
|
+
'..'
|
|
44
|
+
)
|
|
45
|
+
} catch (e) {
|
|
46
|
+
throw new Error('@things-factory/builder module not found.', e)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug('FactoryShell Module Path', ShellModulePath)
|
|
50
|
+
debug('External Module Path', NodeModulePath)
|
|
51
|
+
debug('External Module Parent Path', NodeModuleParentPath)
|
|
52
|
+
debug('Builder Module Path', BuilderModulePath)
|
|
53
|
+
|
|
54
|
+
const ShellPackage = require(path.resolve(ShellModulePath, 'package.json'))
|
|
55
|
+
|
|
56
|
+
/* check if application root has _index.html for override template */
|
|
57
|
+
try {
|
|
58
|
+
if (fs.existsSync(path.resolve(appRootPath, '_index.html'))) {
|
|
59
|
+
var TemplatePath = path.resolve(appRootPath, '_index.html')
|
|
60
|
+
} else {
|
|
61
|
+
var TemplatePath = path.resolve(ShellModulePath, '_index.html')
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
var TemplatePath = path.resolve(ShellModulePath, '_index.html')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let entries = Object.assign({}, EntryBuilder(), {
|
|
68
|
+
main: [
|
|
69
|
+
path.resolve(ShellModulePath, 'client', 'index.js'),
|
|
70
|
+
'@hatiolab/webpack-hot-client/client?path=/__webpack_hmr&timeout=20000&reload=true'
|
|
71
|
+
],
|
|
72
|
+
'headless-scene-components': [path.resolve(ShellModulePath, '.', 'client', 'scene', 'scene-components.js')],
|
|
73
|
+
'scene-viewer': [path.resolve(ShellModulePath, '.', 'client', 'scene', 'scene-viewer.js')]
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
mode: 'development',
|
|
78
|
+
entry: entries,
|
|
79
|
+
resolve: {
|
|
80
|
+
aliasFields: ['browser'],
|
|
81
|
+
alias: {
|
|
82
|
+
[AppPackage.name]:
|
|
83
|
+
AppPackage.name == '@hatiolab/things-scene' ? path.resolve(appRootPath, 'src', 'index.js') : appRootPath
|
|
84
|
+
},
|
|
85
|
+
extensions: ['.ts', '.js', '.jsx', '.tsx', '.json'],
|
|
86
|
+
modules: [NodeModulePath]
|
|
87
|
+
},
|
|
88
|
+
resolveLoader: {
|
|
89
|
+
modules: [path.resolve(BuilderModulePath, 'web-loaders'), NodeModulePath]
|
|
90
|
+
},
|
|
91
|
+
externals:
|
|
92
|
+
AppPackage.name == '@hatiolab/things-scene'
|
|
93
|
+
? {}
|
|
94
|
+
: {
|
|
95
|
+
'@hatiolab/things-scene': 'scene'
|
|
96
|
+
},
|
|
97
|
+
output: {
|
|
98
|
+
path: OUTPUT_PATH,
|
|
99
|
+
filename: 'fmsim/[name].js',
|
|
100
|
+
chunkFilename: 'fmsim/[name].js',
|
|
101
|
+
publicPath: '/'
|
|
102
|
+
},
|
|
103
|
+
module: {
|
|
104
|
+
rules: [
|
|
105
|
+
{
|
|
106
|
+
test: /\.(ts|js)x?$/,
|
|
107
|
+
use: [
|
|
108
|
+
{
|
|
109
|
+
loader: 'babel-loader',
|
|
110
|
+
options: {
|
|
111
|
+
rootMode: 'upward',
|
|
112
|
+
cacheDirectory: true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
test: /\.mjs$/,
|
|
119
|
+
type: 'javascript/auto'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
test: /\.(gif|jpe?g|png|svg)$/,
|
|
123
|
+
type: 'asset/resource',
|
|
124
|
+
generator: {
|
|
125
|
+
filename: 'fmsim/[hash][ext][query]'
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
test: /\.(sa|sc|c)ss$/,
|
|
130
|
+
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
test: /\.less$/,
|
|
134
|
+
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
test: /\.bpmn$/,
|
|
138
|
+
use: 'raw-loader'
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
test: /module-importer.import$/,
|
|
142
|
+
use: {
|
|
143
|
+
loader: 'things-factory-module-loader',
|
|
144
|
+
options: {
|
|
145
|
+
module_path: NodeModulePath
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
test: /things-scene-components.import$/,
|
|
151
|
+
use: [
|
|
152
|
+
{
|
|
153
|
+
loader: 'babel-loader',
|
|
154
|
+
options: {
|
|
155
|
+
rootMode: 'upward',
|
|
156
|
+
cacheDirectory: true
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
loader: 'things-scene-webpack-loader',
|
|
161
|
+
options: {
|
|
162
|
+
module_path: NodeModulePath
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
test: /things-scene-components-with-tools.import$/,
|
|
169
|
+
use: [
|
|
170
|
+
{
|
|
171
|
+
loader: 'babel-loader',
|
|
172
|
+
options: {
|
|
173
|
+
rootMode: 'upward',
|
|
174
|
+
cacheDirectory: true
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
loader: 'things-scene-config-webpack-loader',
|
|
179
|
+
options: {
|
|
180
|
+
module_path: NodeModulePath
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
plugins: [
|
|
188
|
+
new ThemeOverridePlugin({
|
|
189
|
+
chunk: 'theme',
|
|
190
|
+
themeFolder: path.join('client', 'themes')
|
|
191
|
+
}),
|
|
192
|
+
new HTMLWebpackPlugin({
|
|
193
|
+
template: TemplatePath,
|
|
194
|
+
/*
|
|
195
|
+
Allows to control how chunks should be sorted before they are included to the HTML.
|
|
196
|
+
Allowed values are 'none' | 'auto' | 'dependency' | 'manual' | {Function}
|
|
197
|
+
*/
|
|
198
|
+
chunksSortMode: 'none',
|
|
199
|
+
chunks: ['main', 'theme']
|
|
200
|
+
}),
|
|
201
|
+
new MiniCssExtractPlugin({
|
|
202
|
+
filename: '[name].css',
|
|
203
|
+
chunkFilename: '[name].[hash].css',
|
|
204
|
+
ignoreOrder: false
|
|
205
|
+
}),
|
|
206
|
+
new CopyWebpackPlugin({
|
|
207
|
+
patterns: [
|
|
208
|
+
{
|
|
209
|
+
from: 'node_modules/@material-design-icons/font/*',
|
|
210
|
+
to: OUTPUT_PATH,
|
|
211
|
+
context: NodeModuleParentPath
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
from: 'node_modules/@fontsource/roboto/**/*',
|
|
215
|
+
to: OUTPUT_PATH,
|
|
216
|
+
context: NodeModuleParentPath
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
from: 'node_modules/@webcomponents/webcomponentsjs/*',
|
|
220
|
+
to: OUTPUT_PATH,
|
|
221
|
+
context: NodeModuleParentPath
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
from: 'node_modules/web-animations-js/web-animations-next.min.js*',
|
|
225
|
+
to: OUTPUT_PATH,
|
|
226
|
+
context: NodeModuleParentPath
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
from: 'node_modules/@hatiolab/things-scene/*.js*',
|
|
230
|
+
to: OUTPUT_PATH,
|
|
231
|
+
noErrorOnMissing: true,
|
|
232
|
+
context: NodeModuleParentPath
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
}),
|
|
236
|
+
new FolderOverridePlugin({
|
|
237
|
+
target: 'views'
|
|
238
|
+
}),
|
|
239
|
+
new FolderOverridePlugin({
|
|
240
|
+
target: 'assets'
|
|
241
|
+
}),
|
|
242
|
+
new FolderOverridePlugin({
|
|
243
|
+
target: 'helps'
|
|
244
|
+
}),
|
|
245
|
+
new I18nBundlerPlugin({
|
|
246
|
+
output: 'translations'
|
|
247
|
+
}),
|
|
248
|
+
new WorkboxWebpackPlugin.InjectManifest({
|
|
249
|
+
swSrc: path.resolve(ShellModulePath, 'client/serviceworker/sw-src.js'),
|
|
250
|
+
swDest: 'service-worker.js',
|
|
251
|
+
maximumFileSizeToCacheInBytes: 50000000,
|
|
252
|
+
exclude: [/^helps\//, /headless/, /openapi/] // exclude help files, headless files
|
|
253
|
+
}),
|
|
254
|
+
new webpack.DefinePlugin({
|
|
255
|
+
'process.env': {
|
|
256
|
+
'NODE-ENV': JSON.stringify('development'),
|
|
257
|
+
'SHELL-VERSION': JSON.stringify(ShellPackage.version),
|
|
258
|
+
'SHELL-LICENSE': JSON.stringify(ShellPackage.license),
|
|
259
|
+
'APP-VERSION': JSON.stringify(AppPackage.version),
|
|
260
|
+
'APP-LICENSE': JSON.stringify(AppPackage.license),
|
|
261
|
+
'APP-NAME': JSON.stringify(AppPackage.name),
|
|
262
|
+
'APP-DESCRIPTION': JSON.stringify(AppPackage.description),
|
|
263
|
+
'APP-TAGLINE': JSON.stringify(AppPackage.tagline)
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
],
|
|
267
|
+
devtool: 'eval-cheap-module-source-map'
|
|
268
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const webpack = require('webpack')
|
|
4
|
+
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
|
5
|
+
const HTMLWebpackPlugin = require('html-webpack-plugin')
|
|
6
|
+
const I18nBundlerPlugin = require('./webpack-plugins/i18n-bundler-plugin')
|
|
7
|
+
const FolderOverridePlugin = require('./webpack-plugins/folder-override-plugin')
|
|
8
|
+
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
|
|
9
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
10
|
+
const ThemeOverridePlugin = require('./webpack-plugins/theme-override-plugin')
|
|
11
|
+
const EntryBuilder = require('./controller/entries-builder')
|
|
12
|
+
|
|
13
|
+
const glob = require('glob')
|
|
14
|
+
const debug = require('debug')('things-factory:builder:webpack.config')
|
|
15
|
+
|
|
16
|
+
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
|
|
17
|
+
|
|
18
|
+
const { appRootPath } = require('@things-factory/env')
|
|
19
|
+
const AppPackage = require(path.resolve(appRootPath, 'package.json'))
|
|
20
|
+
|
|
21
|
+
const OUTPUT_PATH = path.resolve(appRootPath, 'dist-app')
|
|
22
|
+
|
|
23
|
+
debug('Output Path: ', OUTPUT_PATH)
|
|
24
|
+
|
|
25
|
+
const module_resolve = require('resolve')
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
let pathName = module_resolve.sync('@things-factory/shell', {
|
|
29
|
+
basedir: process.cwd()
|
|
30
|
+
})
|
|
31
|
+
var ShellModulePath = path.resolve(pathName, '../..')
|
|
32
|
+
var NodeModulePath = path.resolve(pathName, '../../../..')
|
|
33
|
+
var NodeModuleParentPath = path.resolve(NodeModulePath, '..')
|
|
34
|
+
} catch (e) {
|
|
35
|
+
throw new Error('@things-factory/shell module not found.', e)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
var BuilderModulePath = path.resolve(
|
|
40
|
+
module_resolve.sync('@things-factory/builder', {
|
|
41
|
+
basedir: process.cwd()
|
|
42
|
+
}),
|
|
43
|
+
'..'
|
|
44
|
+
)
|
|
45
|
+
} catch (e) {
|
|
46
|
+
throw new Error('@things-factory/builder module not found.', e)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug('FactoryShell Module Path', ShellModulePath)
|
|
50
|
+
debug('External Module Path', NodeModulePath)
|
|
51
|
+
debug('External Module Parent Path', NodeModuleParentPath)
|
|
52
|
+
debug('Builder Module Path', BuilderModulePath)
|
|
53
|
+
|
|
54
|
+
const ShellPackage = require(path.resolve(ShellModulePath, 'package.json'))
|
|
55
|
+
|
|
56
|
+
/* check if application root has _index.html for override template */
|
|
57
|
+
try {
|
|
58
|
+
if (fs.existsSync(path.resolve(appRootPath, '_index.html'))) {
|
|
59
|
+
var TemplatePath = path.resolve(appRootPath, '_index.html')
|
|
60
|
+
} else {
|
|
61
|
+
var TemplatePath = path.resolve(ShellModulePath, '_index.html')
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
var TemplatePath = path.resolve(ShellModulePath, '_index.html')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
debug('Index.html TemplatePath', TemplatePath)
|
|
68
|
+
|
|
69
|
+
let entries = Object.assign({}, EntryBuilder(), {
|
|
70
|
+
main: path.resolve(ShellModulePath, 'client', 'index.js'),
|
|
71
|
+
'headless-scene-components': [path.resolve(ShellModulePath, '.', 'client', 'scene', 'scene-components.js')],
|
|
72
|
+
'scene-viewer': [path.resolve(ShellModulePath, '.', 'client', 'scene', 'scene-viewer.js')]
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
mode: 'production',
|
|
77
|
+
entry: entries,
|
|
78
|
+
resolve: {
|
|
79
|
+
aliasFields: ['browser'],
|
|
80
|
+
alias: {
|
|
81
|
+
[AppPackage.name]:
|
|
82
|
+
AppPackage.name == '@hatiolab/things-scene' ? path.resolve(appRootPath, 'src', 'index.js') : appRootPath
|
|
83
|
+
},
|
|
84
|
+
extensions: ['.ts', '.js', '.jsx', '.tsx', '.json'],
|
|
85
|
+
modules: [NodeModulePath]
|
|
86
|
+
},
|
|
87
|
+
resolveLoader: {
|
|
88
|
+
modules: [path.resolve(BuilderModulePath, 'web-loaders'), NodeModulePath]
|
|
89
|
+
},
|
|
90
|
+
externals:
|
|
91
|
+
AppPackage.name == '@hatiolab/things-scene'
|
|
92
|
+
? {}
|
|
93
|
+
: {
|
|
94
|
+
'@hatiolab/things-scene': 'scene'
|
|
95
|
+
},
|
|
96
|
+
output: {
|
|
97
|
+
path: OUTPUT_PATH,
|
|
98
|
+
filename: 'fmsim/[name].js',
|
|
99
|
+
chunkFilename: 'fmsim/[name].js',
|
|
100
|
+
publicPath: '/'
|
|
101
|
+
},
|
|
102
|
+
module: {
|
|
103
|
+
rules: [
|
|
104
|
+
{
|
|
105
|
+
test: /\.(ts|js)x?$/,
|
|
106
|
+
use: [
|
|
107
|
+
{
|
|
108
|
+
loader: 'babel-loader',
|
|
109
|
+
options: {
|
|
110
|
+
rootMode: 'upward',
|
|
111
|
+
cacheDirectory: true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
test: /\.mjs$/,
|
|
118
|
+
type: 'javascript/auto'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
test: /\.(gif|jpe?g|png|svg)$/,
|
|
122
|
+
type: 'asset/resource',
|
|
123
|
+
generator: {
|
|
124
|
+
filename: 'fmsim/[hash][ext][query]'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
test: /\.(sa|sc|c)ss$/,
|
|
129
|
+
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
test: /\.less$/,
|
|
133
|
+
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
test: /module-importer.import$/,
|
|
137
|
+
use: {
|
|
138
|
+
loader: 'things-factory-module-loader',
|
|
139
|
+
options: {
|
|
140
|
+
module_path: NodeModulePath
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
test: /things-scene-components.import$/,
|
|
146
|
+
use: [
|
|
147
|
+
{
|
|
148
|
+
loader: 'babel-loader',
|
|
149
|
+
options: {
|
|
150
|
+
rootMode: 'upward',
|
|
151
|
+
cacheDirectory: true
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
loader: 'things-scene-webpack-loader',
|
|
156
|
+
options: {
|
|
157
|
+
module_path: NodeModulePath
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
test: /things-scene-components-with-tools.import$/,
|
|
164
|
+
use: [
|
|
165
|
+
{
|
|
166
|
+
loader: 'babel-loader',
|
|
167
|
+
options: {
|
|
168
|
+
rootMode: 'upward',
|
|
169
|
+
cacheDirectory: true
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
loader: 'things-scene-config-webpack-loader',
|
|
174
|
+
options: {
|
|
175
|
+
module_path: NodeModulePath
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
plugins: [
|
|
183
|
+
new ThemeOverridePlugin({
|
|
184
|
+
chunk: 'theme',
|
|
185
|
+
themeFolder: path.join('client', 'themes')
|
|
186
|
+
}),
|
|
187
|
+
new HTMLWebpackPlugin({
|
|
188
|
+
template: TemplatePath,
|
|
189
|
+
/*
|
|
190
|
+
Allows to control how chunks should be sorted before they are included to the HTML.
|
|
191
|
+
Allowed values are 'none' | 'auto' | 'dependency' | 'manual' | {Function}
|
|
192
|
+
*/
|
|
193
|
+
chunksSortMode: 'none',
|
|
194
|
+
chunks: ['main', 'theme']
|
|
195
|
+
}),
|
|
196
|
+
new MiniCssExtractPlugin({
|
|
197
|
+
// Options similar to the same options in webpackOptions.output
|
|
198
|
+
// all options are optional
|
|
199
|
+
filename: 'fmsim/[name].css',
|
|
200
|
+
chunkFilename: 'fmsim/[name].[hash].css',
|
|
201
|
+
ignoreOrder: false // Enable to remove warnings about conflicting order
|
|
202
|
+
}),
|
|
203
|
+
new CopyWebpackPlugin({
|
|
204
|
+
patterns: [
|
|
205
|
+
{
|
|
206
|
+
from: 'node_modules/@material-design-icons/font/*',
|
|
207
|
+
to: OUTPUT_PATH + '/fmsim',
|
|
208
|
+
context: NodeModuleParentPath
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
from: 'node_modules/@fontsource/roboto/**/*',
|
|
212
|
+
to: OUTPUT_PATH + '/fmsim',
|
|
213
|
+
context: NodeModuleParentPath
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
from: 'node_modules/@webcomponents/webcomponentsjs/*',
|
|
217
|
+
to: OUTPUT_PATH + '/fmsim',
|
|
218
|
+
context: NodeModuleParentPath
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
from: 'node_modules/web-animations-js/web-animations-next.min.js*',
|
|
222
|
+
to: OUTPUT_PATH + '/fmsim',
|
|
223
|
+
context: NodeModuleParentPath
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
from: 'node_modules/@hatiolab/things-scene/*.js*',
|
|
227
|
+
to: OUTPUT_PATH + '/fmsim',
|
|
228
|
+
noErrorOnMissing: true,
|
|
229
|
+
context: NodeModuleParentPath
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}),
|
|
233
|
+
new FolderOverridePlugin({
|
|
234
|
+
target: 'views'
|
|
235
|
+
}),
|
|
236
|
+
new FolderOverridePlugin({
|
|
237
|
+
target: 'assets'
|
|
238
|
+
}),
|
|
239
|
+
new FolderOverridePlugin({
|
|
240
|
+
target: 'helps'
|
|
241
|
+
}),
|
|
242
|
+
new I18nBundlerPlugin({
|
|
243
|
+
output: 'translations'
|
|
244
|
+
}),
|
|
245
|
+
new WorkboxWebpackPlugin.InjectManifest({
|
|
246
|
+
swSrc: path.resolve(ShellModulePath, 'client/serviceworker/sw-src.js'),
|
|
247
|
+
swDest: 'service-worker.js',
|
|
248
|
+
maximumFileSizeToCacheInBytes: 50000000,
|
|
249
|
+
exclude: [/^helps\//, /headless/, /openapi/] // exclude help files, headless files
|
|
250
|
+
}),
|
|
251
|
+
new webpack.DefinePlugin({
|
|
252
|
+
'process.env': {
|
|
253
|
+
'NODE-ENV': JSON.stringify('production'),
|
|
254
|
+
'SHELL-VERSION': JSON.stringify(ShellPackage.version),
|
|
255
|
+
'SHELL-LICENSE': JSON.stringify(ShellPackage.license),
|
|
256
|
+
'APP-VERSION': JSON.stringify(AppPackage.version),
|
|
257
|
+
'APP-LICENSE': JSON.stringify(AppPackage.license),
|
|
258
|
+
'APP-NAME': JSON.stringify(AppPackage.name),
|
|
259
|
+
'APP-DESCRIPTION': JSON.stringify(AppPackage.description),
|
|
260
|
+
'APP-TAGLINE': JSON.stringify(AppPackage.tagline)
|
|
261
|
+
}
|
|
262
|
+
}),
|
|
263
|
+
new NodePolyfillPlugin()
|
|
264
|
+
]
|
|
265
|
+
}
|