mirror of
https://github.com/Eugeny/tabby-web.git
synced 2025-07-22 10:58:03 +00:00
wip
This commit is contained in:
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
123
.eslintrc.yml
Normal file
123
.eslintrc.yml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
parser: '@typescript-eslint/parser'
|
||||||
|
parserOptions:
|
||||||
|
project:
|
||||||
|
- tsconfig.json
|
||||||
|
- '*/tsconfig.typings.json'
|
||||||
|
extends:
|
||||||
|
- 'plugin:@typescript-eslint/all'
|
||||||
|
plugins:
|
||||||
|
- '@typescript-eslint'
|
||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
es6: true
|
||||||
|
node: true
|
||||||
|
commonjs: true
|
||||||
|
rules:
|
||||||
|
'@typescript-eslint/semi':
|
||||||
|
- error
|
||||||
|
- never
|
||||||
|
'@typescript-eslint/indent':
|
||||||
|
- error
|
||||||
|
- 4
|
||||||
|
'@typescript-eslint/explicit-member-accessibility':
|
||||||
|
- error
|
||||||
|
- accessibility: no-public
|
||||||
|
overrides:
|
||||||
|
parameterProperties: explicit
|
||||||
|
'@typescript-eslint/no-require-imports': off
|
||||||
|
'@typescript-eslint/no-parameter-properties': off
|
||||||
|
'@typescript-eslint/explicit-function-return-type': off
|
||||||
|
'@typescript-eslint/no-explicit-any': off
|
||||||
|
'@typescript-eslint/no-magic-numbers': off
|
||||||
|
'@typescript-eslint/member-delimiter-style': off
|
||||||
|
'@typescript-eslint/promise-function-async': off
|
||||||
|
'@typescript-eslint/require-array-sort-compare': off
|
||||||
|
'@typescript-eslint/no-floating-promises': off
|
||||||
|
'@typescript-eslint/prefer-readonly': off
|
||||||
|
'@typescript-eslint/require-await': off
|
||||||
|
'@typescript-eslint/strict-boolean-expressions': off
|
||||||
|
'@typescript-eslint/no-misused-promises':
|
||||||
|
- error
|
||||||
|
- checksVoidReturn: false
|
||||||
|
'@typescript-eslint/typedef': off
|
||||||
|
'@typescript-eslint/consistent-type-imports': off
|
||||||
|
'@typescript-eslint/sort-type-union-intersection-members': off
|
||||||
|
'@typescript-eslint/no-use-before-define':
|
||||||
|
- error
|
||||||
|
- classes: false
|
||||||
|
no-duplicate-imports: error
|
||||||
|
array-bracket-spacing:
|
||||||
|
- error
|
||||||
|
- never
|
||||||
|
block-scoped-var: error
|
||||||
|
brace-style: off
|
||||||
|
'@typescript-eslint/brace-style':
|
||||||
|
- error
|
||||||
|
- 1tbs
|
||||||
|
- allowSingleLine: true
|
||||||
|
computed-property-spacing:
|
||||||
|
- error
|
||||||
|
- never
|
||||||
|
comma-dangle: off
|
||||||
|
'@typescript-eslint/comma-dangle':
|
||||||
|
- error
|
||||||
|
- always-multiline
|
||||||
|
curly: error
|
||||||
|
eol-last: error
|
||||||
|
eqeqeq:
|
||||||
|
- error
|
||||||
|
- smart
|
||||||
|
max-depth:
|
||||||
|
- 1
|
||||||
|
- 5
|
||||||
|
max-statements:
|
||||||
|
- 1
|
||||||
|
- 80
|
||||||
|
no-multiple-empty-lines: error
|
||||||
|
no-mixed-spaces-and-tabs: error
|
||||||
|
no-trailing-spaces: error
|
||||||
|
'@typescript-eslint/no-unused-vars':
|
||||||
|
- error
|
||||||
|
- vars: all
|
||||||
|
args: after-used
|
||||||
|
argsIgnorePattern: ^_
|
||||||
|
no-undef: error
|
||||||
|
no-var: error
|
||||||
|
object-curly-spacing: off
|
||||||
|
'@typescript-eslint/object-curly-spacing':
|
||||||
|
- error
|
||||||
|
- always
|
||||||
|
quote-props:
|
||||||
|
- warn
|
||||||
|
- as-needed
|
||||||
|
- keywords: true
|
||||||
|
numbers: true
|
||||||
|
quotes: off
|
||||||
|
'@typescript-eslint/quotes':
|
||||||
|
- error
|
||||||
|
- single
|
||||||
|
- allowTemplateLiterals: true
|
||||||
|
'@typescript-eslint/no-confusing-void-expression':
|
||||||
|
- error
|
||||||
|
- ignoreArrowShorthand: true
|
||||||
|
'@typescript-eslint/no-non-null-assertion': off
|
||||||
|
'@typescript-eslint/no-unnecessary-condition':
|
||||||
|
- error
|
||||||
|
- allowConstantLoopConditions: true
|
||||||
|
'@typescript-eslint/restrict-template-expressions': off
|
||||||
|
'@typescript-eslint/prefer-readonly-parameter-types': off
|
||||||
|
'@typescript-eslint/no-unsafe-member-access': off
|
||||||
|
'@typescript-eslint/no-unsafe-call': off
|
||||||
|
'@typescript-eslint/no-unsafe-return': off
|
||||||
|
'@typescript-eslint/no-unsafe-assignment': off
|
||||||
|
'@typescript-eslint/naming-convention': off
|
||||||
|
'@typescript-eslint/lines-between-class-members':
|
||||||
|
- error
|
||||||
|
- exceptAfterSingleLine: true
|
||||||
|
'@typescript-eslint/dot-notation': off
|
||||||
|
'@typescript-eslint/no-implicit-any-catch': off
|
||||||
|
'@typescript-eslint/member-ordering': off
|
||||||
|
'@typescript-eslint/no-var-requires': off
|
||||||
|
'@typescript-eslint/no-unsafe-argument': off
|
||||||
|
'@typescript-eslint/restrict-plus-operands': off
|
||||||
|
'@typescript-eslint/space-infix-ops': off
|
13
package.json
13
package.json
@@ -4,10 +4,11 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --progress",
|
"build": "webpack --progress",
|
||||||
"watch": "DEV=1 webpack --progress --watch",
|
"watch": "BACKEND_URL=http://localhost:8001 DEV=1 webpack --progress --watch",
|
||||||
"build:server": "webpack --progress -c webpack.server.config.js",
|
"build:server": "webpack --progress -c webpack.config.server.js",
|
||||||
"watch:server": "DEV=1 webpack --progress --watch -c webpack.server.config.js",
|
"watch:server": "DEV=1 webpack --progress --watch -c webpack.config.server.js",
|
||||||
"start": "./manage.py runserver"
|
"start": "./manage.py runserver 8001",
|
||||||
|
"start:server": "PORT=8000 node build-server/server.js"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -32,6 +33,8 @@
|
|||||||
"@ngtools/webpack": "^12.0.4",
|
"@ngtools/webpack": "^12.0.4",
|
||||||
"@tabby-gang/to-string-loader": "^1.1.7-beta.1",
|
"@tabby-gang/to-string-loader": "^1.1.7-beta.1",
|
||||||
"@types/node": "^11.9.5",
|
"@types/node": "^11.9.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
||||||
|
"@typescript-eslint/parser": "^4.28.4",
|
||||||
"apply-loader": "^2.0.0",
|
"apply-loader": "^2.0.0",
|
||||||
"awesome-typescript-loader": "^5.2.1",
|
"awesome-typescript-loader": "^5.2.1",
|
||||||
"bootstrap": "^5.0.1",
|
"bootstrap": "^5.0.1",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"core-js": "^3.14.0",
|
"core-js": "^3.14.0",
|
||||||
"css-loader": "^2.1.0",
|
"css-loader": "^2.1.0",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
|
"eslint": "^7.31.0",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"html-loader": "^2.1.2",
|
"html-loader": "^2.1.2",
|
||||||
"html-webpack-plugin": "^5.3.2",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
@@ -63,6 +67,7 @@
|
|||||||
"webpack": "^5.38.1",
|
"webpack": "^5.38.1",
|
||||||
"webpack-bundle-analyzer": "^4.4.2",
|
"webpack-bundle-analyzer": "^4.4.2",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.7.2",
|
||||||
|
"webpack-node-externals": "^3.0.0",
|
||||||
"zone.js": "^0.11.4"
|
"zone.js": "^0.11.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
17
poetry.lock
generated
17
poetry.lock
generated
@@ -237,6 +237,17 @@ sqlparse = ">=0.2.2"
|
|||||||
argon2 = ["argon2-cffi (>=19.1.0)"]
|
argon2 = ["argon2-cffi (>=19.1.0)"]
|
||||||
bcrypt = ["bcrypt"]
|
bcrypt = ["bcrypt"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-cors-headers"
|
||||||
|
version = "3.7.0"
|
||||||
|
description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Django = ">=2.2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-rest-framework"
|
name = "django-rest-framework"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -852,7 +863,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
content-hash = "198155cefe870371fb615a4787e9117dd1f1b9ea25116df55741b1dcd4eb2c12"
|
content-hash = "cc070c0414bb554395cbc518a5857a6f239ad17b1573c27012441cef86320b7a"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
appdirs = [
|
appdirs = [
|
||||||
@@ -984,6 +995,10 @@ django = [
|
|||||||
{file = "Django-3.2.3-py3-none-any.whl", hash = "sha256:7e0a1393d18c16b503663752a8b6790880c5084412618990ce8a81cc908b4962"},
|
{file = "Django-3.2.3-py3-none-any.whl", hash = "sha256:7e0a1393d18c16b503663752a8b6790880c5084412618990ce8a81cc908b4962"},
|
||||||
{file = "Django-3.2.3.tar.gz", hash = "sha256:13ac78dbfd189532cad8f383a27e58e18b3d33f80009ceb476d7fcbfc5dcebd8"},
|
{file = "Django-3.2.3.tar.gz", hash = "sha256:13ac78dbfd189532cad8f383a27e58e18b3d33f80009ceb476d7fcbfc5dcebd8"},
|
||||||
]
|
]
|
||||||
|
django-cors-headers = [
|
||||||
|
{file = "django-cors-headers-3.7.0.tar.gz", hash = "sha256:96069c4aaacace786a34ee7894ff680780ec2644e4268b31181044410fecd12e"},
|
||||||
|
{file = "django_cors_headers-3.7.0-py3-none-any.whl", hash = "sha256:1ac2b1213de75a251e2ba04448da15f99bcfcbe164288ae6b5ff929dc49b372f"},
|
||||||
|
]
|
||||||
django-rest-framework = [
|
django-rest-framework = [
|
||||||
{file = "django-rest-framework-0.1.0.tar.gz", hash = "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a"},
|
{file = "django-rest-framework-0.1.0.tar.gz", hash = "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a"},
|
||||||
]
|
]
|
||||||
|
@@ -23,6 +23,7 @@ Twisted = "20.3.0"
|
|||||||
semver = "^2.13.0"
|
semver = "^2.13.0"
|
||||||
requests = "^2.25.1"
|
requests = "^2.25.1"
|
||||||
pyga = "^2.6.2"
|
pyga = "^2.6.2"
|
||||||
|
django-cors-headers = "^3.7.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
flake8 = "^3.9.2"
|
flake8 = "^3.9.2"
|
||||||
|
@@ -5,10 +5,11 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http'
|
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http'
|
||||||
import { ClipboardModule } from '@angular/cdk/clipboard'
|
import { ClipboardModule } from '@angular/cdk/clipboard'
|
||||||
import { TransferHttpCacheModule } from '@nguniversal/common'
|
import { TransferHttpCacheModule } from '@nguniversal/common'
|
||||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'
|
||||||
|
import { UniversalInterceptor } from './interceptor'
|
||||||
import { AppComponent } from './components/app.component'
|
import { AppComponent } from './components/app.component'
|
||||||
import { MainComponent } from './components/main.component'
|
import { MainComponent } from './components/main.component'
|
||||||
import { ConfigModalComponent } from './components/configModal.component'
|
import { ConfigModalComponent } from './components/configModal.component'
|
||||||
@@ -17,7 +18,7 @@ import { HomeComponent } from './components/home.component'
|
|||||||
import { LoginComponent } from './components/login.component'
|
import { LoginComponent } from './components/login.component'
|
||||||
import { InstanceInfoResolver } from './api'
|
import { InstanceInfoResolver } from './api'
|
||||||
|
|
||||||
import '@fortawesome/fontawesome-svg-core/styles.css'
|
// import '@fortawesome/fontawesome-svg-core/styles.css'
|
||||||
|
|
||||||
const ROUTES = [
|
const ROUTES = [
|
||||||
{
|
{
|
||||||
@@ -25,28 +26,28 @@ const ROUTES = [
|
|||||||
component: HomeComponent,
|
component: HomeComponent,
|
||||||
resolve: {
|
resolve: {
|
||||||
instanceInfo: InstanceInfoResolver,
|
instanceInfo: InstanceInfoResolver,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'app',
|
path: 'app',
|
||||||
component: MainComponent,
|
component: MainComponent,
|
||||||
resolve: {
|
resolve: {
|
||||||
instanceInfo: InstanceInfoResolver,
|
instanceInfo: InstanceInfoResolver,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: LoginComponent,
|
component: LoginComponent,
|
||||||
resolve: {
|
resolve: {
|
||||||
instanceInfo: InstanceInfoResolver,
|
instanceInfo: InstanceInfoResolver,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule.withServerTransition({
|
BrowserModule.withServerTransition({
|
||||||
appId: 'tabby'
|
appId: 'tabby',
|
||||||
}),
|
}),
|
||||||
TransferHttpCacheModule,
|
TransferHttpCacheModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
@@ -60,6 +61,13 @@ const ROUTES = [
|
|||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
RouterModule.forRoot(ROUTES),
|
RouterModule.forRoot(ROUTES),
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: UniversalInterceptor,
|
||||||
|
multi: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
MainComponent,
|
MainComponent,
|
||||||
@@ -68,6 +76,6 @@ const ROUTES = [
|
|||||||
ConfigModalComponent,
|
ConfigModalComponent,
|
||||||
SettingsModalComponent,
|
SettingsModalComponent,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import { HTTP_INTERCEPTORS } from '@angular/common/http'
|
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'
|
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'
|
||||||
import { AppModule } from './app.module'
|
import { AppModule } from './app.module'
|
||||||
import { AppComponent } from './components/app.component'
|
import { AppComponent } from './components/app.component'
|
||||||
import { UniversalInterceptor } from './ssr-interceptor'
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -13,13 +11,6 @@ import { UniversalInterceptor } from './ssr-interceptor'
|
|||||||
ServerModule,
|
ServerModule,
|
||||||
ServerTransferStateModule,
|
ServerTransferStateModule,
|
||||||
],
|
],
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: HTTP_INTERCEPTORS,
|
|
||||||
useClass: UniversalInterceptor,
|
|
||||||
multi: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// Since the bootstrapped component is not inherited from your
|
// Since the bootstrapped component is not inherited from your
|
||||||
// imported AppModule, it needs to be repeated here.
|
// imported AppModule, it needs to be repeated here.
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
@@ -6,11 +6,18 @@ import { InstanceInfo, Version } from '../api'
|
|||||||
import { faCoffee, faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons'
|
import { faCoffee, faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { ActivatedRoute } from '@angular/router'
|
import { ActivatedRoute } from '@angular/router'
|
||||||
|
import { CommonService } from '../services/common.service'
|
||||||
|
|
||||||
|
|
||||||
class DemoConnector {
|
class DemoConnector {
|
||||||
constructor (targetWindow: Window, private version: Version) {
|
constructor (
|
||||||
targetWindow['tabbyWebDemoDataPath'] = `${this.getDistURL()}/${version.version}/tabby-web-demo/data`
|
targetWindow: Window,
|
||||||
|
private commonService: CommonService,
|
||||||
|
private version: Version,
|
||||||
|
) {
|
||||||
|
this.getDistURL().then(distURL => {
|
||||||
|
targetWindow['tabbyWebDemoDataPath'] = `${distURL}/${version.version}/tabby-web-demo/data`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadConfig (): Promise<string> {
|
async loadConfig (): Promise<string> {
|
||||||
@@ -22,15 +29,15 @@ class DemoConnector {
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveConfig (content: string): Promise<void> {
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
}
|
async saveConfig (_content: string): Promise<void> { }
|
||||||
|
|
||||||
getAppVersion (): string {
|
getAppVersion (): string {
|
||||||
return this.version.version
|
return this.version.version
|
||||||
}
|
}
|
||||||
|
|
||||||
getDistURL (): string {
|
async getDistURL (): Promise<string> {
|
||||||
return '/app-dist'
|
return await this.commonService.getBackendURL() + '/app-dist'
|
||||||
}
|
}
|
||||||
|
|
||||||
getPluginsToLoad (): string[] {
|
getPluginsToLoad (): string[] {
|
||||||
@@ -94,12 +101,14 @@ export class HomeComponent {
|
|||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
private commonService: CommonService,
|
||||||
route: ActivatedRoute,
|
route: ActivatedRoute,
|
||||||
) {
|
) {
|
||||||
window.addEventListener('message', this.connectorRequestHandler)
|
window.addEventListener('message', this.connectorRequestHandler)
|
||||||
this.instanceInfo = route.snapshot.data.instanceInfo
|
this.instanceInfo = route.snapshot.data.instanceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
connectorRequestHandler = event => {
|
connectorRequestHandler = event => {
|
||||||
if (event.data === 'request-connector') {
|
if (event.data === 'request-connector') {
|
||||||
this.iframe.nativeElement.contentWindow['__connector__'] = this.connector
|
this.iframe.nativeElement.contentWindow['__connector__'] = this.connector
|
||||||
@@ -107,14 +116,14 @@ export class HomeComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngAfterViewInit () {
|
async ngAfterViewInit (): Promise<void> {
|
||||||
const versions = await this.http.get('/api/1/versions').toPromise()
|
const versions = await this.http.get('/api/1/versions').toPromise()
|
||||||
versions.sort((a, b) => -semverCompare(a.version, b.version))
|
versions.sort((a, b) => -semverCompare(a.version, b.version))
|
||||||
this.connector = new DemoConnector(this.iframe.nativeElement.contentWindow, versions[0])
|
this.connector = new DemoConnector(this.iframe.nativeElement.contentWindow, this.commonService, versions[0])
|
||||||
this.iframe.nativeElement.src = '/terminal'
|
this.iframe.nativeElement.src = '/terminal.html'
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy (): void {
|
||||||
window.removeEventListener('message', this.connectorRequestHandler)
|
window.removeEventListener('message', this.connectorRequestHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ export class MainComponent {
|
|||||||
|
|
||||||
async loadApp (config, version) {
|
async loadApp (config, version) {
|
||||||
this.showApp = true
|
this.showApp = true
|
||||||
this.iframe.nativeElement.src = '/terminal'
|
this.iframe.nativeElement.src = '/terminal.html'
|
||||||
await this.http.patch(`/api/1/configs/${config.id}`, {
|
await this.http.patch(`/api/1/configs/${config.id}`, {
|
||||||
last_used_with_version: version.version,
|
last_used_with_version: version.version,
|
||||||
}).toPromise()
|
}).toPromise()
|
||||||
|
24
src/interceptor.ts
Normal file
24
src/interceptor.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'
|
||||||
|
import { Observable, from } from 'rxjs'
|
||||||
|
import { switchMap } from 'rxjs/operators'
|
||||||
|
import { CommonService } from './services/common.service'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UniversalInterceptor implements HttpInterceptor {
|
||||||
|
constructor (private commonService: CommonService) { }
|
||||||
|
|
||||||
|
intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
if (!request.url.startsWith('//') && request.url.startsWith('/')) {
|
||||||
|
return from(this.commonService.getBackendURL()).pipe(switchMap((baseUrl: string) => {
|
||||||
|
const endpoint = request.url
|
||||||
|
|
||||||
|
request = request.clone({
|
||||||
|
url: `${baseUrl}${endpoint}`,
|
||||||
|
})
|
||||||
|
return next.handle(request)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return next.handle(request)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +1,13 @@
|
|||||||
import 'zone.js/dist/zone-node';
|
|
||||||
import { enableProdMode } from '@angular/core';
|
|
||||||
|
|
||||||
require('source-map-support').install()
|
require('source-map-support').install()
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone-node';
|
||||||
|
import './ssr-polyfills'
|
||||||
|
|
||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
|
||||||
// Express Engine
|
// Express Engine
|
||||||
import { ngExpressEngine } from '@nguniversal/express-engine';
|
import { ngExpressEngine } from '@nguniversal/express-engine';
|
||||||
|
|
||||||
import './ssr-polyfills'
|
|
||||||
|
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
@@ -37,15 +38,15 @@ app.use('/static', express.static(DIST_FOLDER, {
|
|||||||
maxAge: '1y'
|
maxAge: '1y'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
var proxy = require('express-http-proxy');
|
// var proxy = require('express-http-proxy');
|
||||||
|
|
||||||
app.get(['/', '/login'], (req, res) => {
|
app.get('*', (req, res) => {
|
||||||
res.render('index', { req });
|
res.render('index', { req });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.use('/', proxy('http://tabby.local:8000/api/', {
|
// app.use('/', proxy('http://tabby.local:8000/api/', {
|
||||||
}))
|
// }))
|
||||||
|
|
||||||
// Start up the Node server
|
// Start up the Node server
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
|
@@ -2,9 +2,10 @@ import { Buffer } from 'buffer'
|
|||||||
import { Subject } from 'rxjs'
|
import { Subject } from 'rxjs'
|
||||||
import { debounceTime } from 'rxjs/operators'
|
import { debounceTime } from 'rxjs/operators'
|
||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable, Injector } from '@angular/core'
|
||||||
import { LoginService } from '../services/login.service'
|
|
||||||
import { Config, Gateway, Version } from '../api'
|
import { Config, Gateway, Version } from '../api'
|
||||||
|
import { LoginService } from './login.service'
|
||||||
|
import { CommonService } from './common.service'
|
||||||
|
|
||||||
export class SocketProxy {
|
export class SocketProxy {
|
||||||
connect$ = new Subject<void>()
|
connect$ = new Subject<void>()
|
||||||
@@ -21,12 +22,21 @@ export class SocketProxy {
|
|||||||
port: number
|
port: number
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (private appConnector: AppConnectorService) { }
|
private appConnector: AppConnectorService
|
||||||
|
private loginService: LoginService
|
||||||
|
|
||||||
async connect (options) {
|
constructor (
|
||||||
|
injector: Injector,
|
||||||
|
) {
|
||||||
|
this.appConnector = injector.get(AppConnectorService)
|
||||||
|
this.loginService = injector.get(LoginService)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
async connect (options: any): Promise<void> {
|
||||||
this.options = options
|
this.options = options
|
||||||
this.url = this.appConnector.loginService.user.custom_connection_gateway
|
this.url = this.loginService.user.custom_connection_gateway
|
||||||
this.authToken = this.appConnector.loginService.user.custom_connection_gateway_token
|
this.authToken = this.loginService.user.custom_connection_gateway_token
|
||||||
if (!this.url) {
|
if (!this.url) {
|
||||||
try {
|
try {
|
||||||
const gateway = await this.appConnector.chooseConnectionGateway()
|
const gateway = await this.appConnector.chooseConnectionGateway()
|
||||||
@@ -120,9 +130,11 @@ export class AppConnectorService {
|
|||||||
sockets: SocketProxy[] = []
|
sockets: SocketProxy[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
private injector: Injector,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public loginService: LoginService,
|
private commonService: CommonService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
this.configUpdate.pipe(debounceTime(1000)).subscribe(async content => {
|
this.configUpdate.pipe(debounceTime(1000)).subscribe(async content => {
|
||||||
const result = await this.http.patch(`/api/1/configs/${this.config.id}`, { content }).toPromise()
|
const result = await this.http.patch(`/api/1/configs/${this.config.id}`, { content }).toPromise()
|
||||||
Object.assign(this.config, result)
|
Object.assign(this.config, result)
|
||||||
@@ -147,8 +159,8 @@ export class AppConnectorService {
|
|||||||
return this.version.version
|
return this.version.version
|
||||||
}
|
}
|
||||||
|
|
||||||
getDistURL (): string {
|
async getDistURL (): Promise<string> {
|
||||||
return '../app-dist'
|
return await this.commonService.getBackendURL() + '/app-dist'
|
||||||
}
|
}
|
||||||
|
|
||||||
getPluginsToLoad (): string[] {
|
getPluginsToLoad (): string[] {
|
||||||
@@ -168,7 +180,7 @@ export class AppConnectorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createSocket () {
|
createSocket () {
|
||||||
const socket = new SocketProxy(this)
|
const socket = new SocketProxy(this.injector)
|
||||||
this.sockets.push(socket)
|
this.sockets.push(socket)
|
||||||
socket.close$.subscribe(() => {
|
socket.close$.subscribe(() => {
|
||||||
this.sockets = this.sockets.filter(x => x !== socket)
|
this.sockets = this.sockets.filter(x => x !== socket)
|
||||||
|
18
src/services/common.service.ts
Normal file
18
src/services/common.service.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class CommonService {
|
||||||
|
private backendURL?: string
|
||||||
|
|
||||||
|
async getBackendURL (): Promise<string> {
|
||||||
|
if (!this.backendURL) {
|
||||||
|
const config = await (await fetch('/config.json')).json()
|
||||||
|
this.backendURL = config.backendURL
|
||||||
|
if (this.backendURL.endsWith('/')) {
|
||||||
|
this.backendURL = this.backendURL.slice(0, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.backendURL
|
||||||
|
}
|
||||||
|
}
|
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* This interceptor ensures that the app makes requests
|
|
||||||
* with relative paths correctly server-side.
|
|
||||||
* Requests which start with a dot (ex. ./assets/...)
|
|
||||||
* or relative ones ( ex. /assets/...) will be converted
|
|
||||||
* to absolute paths
|
|
||||||
*/
|
|
||||||
import { Inject, Injectable, Injector, PLATFORM_ID } from '@angular/core';
|
|
||||||
import { isPlatformServer } from '@angular/common';
|
|
||||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
|
||||||
import { REQUEST } from '@nguniversal/express-engine/tokens';
|
|
||||||
|
|
||||||
import { Request } from 'express';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UniversalInterceptor implements HttpInterceptor {
|
|
||||||
constructor(
|
|
||||||
private readonly injector: Injector,
|
|
||||||
@Inject(PLATFORM_ID) private readonly platformId: any) {
|
|
||||||
}
|
|
||||||
|
|
||||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
|
||||||
const isServer = isPlatformServer(this.platformId);
|
|
||||||
|
|
||||||
if (isServer && !request.url.startsWith('//') && (request.url.startsWith('./') || request.url.startsWith('/'))) {
|
|
||||||
const serverRequest = this.injector.get(REQUEST) as Request;
|
|
||||||
console.log(serverRequest)
|
|
||||||
const baseUrl = `${serverRequest.protocol}://${serverRequest.get('Host')}`;
|
|
||||||
let endpoint = request.url;
|
|
||||||
/**
|
|
||||||
* ISSUE https://github.com/angular/angular/issues/19224
|
|
||||||
* HttpClient doesn't support relative requests server-side
|
|
||||||
*/
|
|
||||||
if (endpoint.startsWith('.')) {
|
|
||||||
endpoint = endpoint.substring(1);
|
|
||||||
}
|
|
||||||
// Now the endpoint starts with '/'
|
|
||||||
request = request.clone({
|
|
||||||
url: `${baseUrl}${endpoint}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return next.handle(request);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,7 +2,7 @@ import * as domino from 'domino';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const template = fs.readFileSync(path.join(process.cwd(), 'build-server', 'index.html')).toString();
|
const template = fs.readFileSync(path.join(process.cwd(), 'build', 'index.html')).toString();
|
||||||
const win = domino.createWindow(template);
|
const win = domino.createWindow(template);
|
||||||
|
|
||||||
global['window'] = win;
|
global['window'] = win;
|
||||||
|
@@ -31,7 +31,7 @@ async function start () {
|
|||||||
await (await fetch(url)).text()
|
await (await fetch(url)).text()
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl = `${connector.getDistURL()}/${appVersion}`
|
const baseUrl = `${await connector.getDistURL()}/${appVersion}`
|
||||||
const coreURLs = [
|
const coreURLs = [
|
||||||
`${baseUrl}/tabby-web-container/dist/preload.js`,
|
`${baseUrl}/tabby-web-container/dist/preload.js`,
|
||||||
`${baseUrl}/tabby-web-container/dist/bundle.js`,
|
`${baseUrl}/tabby-web-container/dist/bundle.js`,
|
||||||
|
@@ -16,9 +16,9 @@ urlpatterns = [
|
|||||||
path('api/1/instance-info', api.InstanceInfoViewSet.as_view({'get': 'retrieve'})),
|
path('api/1/instance-info', api.InstanceInfoViewSet.as_view({'get': 'retrieve'})),
|
||||||
path('api/1/gateways/choose', api.ChooseGatewayViewSet.as_view({'post': 'retrieve'})),
|
path('api/1/gateways/choose', api.ChooseGatewayViewSet.as_view({'post': 'retrieve'})),
|
||||||
|
|
||||||
re_path('^(|login|app)$', views.IndexView.as_view()),
|
# re_path('^(|login|app)$', views.IndexView.as_view()),
|
||||||
|
|
||||||
path('terminal', views.TerminalView.as_view()),
|
# path('terminal', views.TerminalView.as_view()),
|
||||||
path('app-dist/<version>/<path:path>', views.AppDistView.as_view()),
|
path('app-dist/<version>/<path:path>', views.AppDistView.as_view()),
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
@@ -35,6 +35,7 @@ INSTALLED_APPS = [
|
|||||||
'channels',
|
'channels',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'social_django',
|
'social_django',
|
||||||
|
'corsheaders',
|
||||||
'tabby.app',
|
'tabby.app',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ MIDDLEWARE = [
|
|||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
'tabby.middleware.TokenMiddleware',
|
'tabby.middleware.TokenMiddleware',
|
||||||
'tabby.middleware.GAMiddleware',
|
'tabby.middleware.GAMiddleware',
|
||||||
]
|
]
|
||||||
@@ -135,15 +137,7 @@ LOGGING = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATIC_ROOT = BASE_DIR / 'static'
|
|
||||||
STATICFILES_DIRS = [BASE_DIR / 'build']
|
|
||||||
|
|
||||||
# Default primary key field type
|
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
@@ -180,9 +174,11 @@ LOGIN_REDIRECT_URL = '/app'
|
|||||||
APP_DIST_PATH = Path(os.getenv('APP_DIST_PATH', BASE_DIR / 'app-dist'))
|
APP_DIST_PATH = Path(os.getenv('APP_DIST_PATH', BASE_DIR / 'app-dist'))
|
||||||
NPM_REGISTRY = os.getenv('NPM_REGISTRY', 'https://registry.npmjs.org').rstrip('/')
|
NPM_REGISTRY = os.getenv('NPM_REGISTRY', 'https://registry.npmjs.org').rstrip('/')
|
||||||
|
|
||||||
|
FRONTEND_URL = None
|
||||||
GITHUB_ELIGIBLE_SPONSORSHIPS = None
|
GITHUB_ELIGIBLE_SPONSORSHIPS = None
|
||||||
|
|
||||||
for key in [
|
for key in [
|
||||||
|
'FRONTEND_URL',
|
||||||
'SOCIAL_AUTH_GITHUB_KEY',
|
'SOCIAL_AUTH_GITHUB_KEY',
|
||||||
'SOCIAL_AUTH_GITHUB_SECRET',
|
'SOCIAL_AUTH_GITHUB_SECRET',
|
||||||
'SOCIAL_AUTH_GITLAB_KEY',
|
'SOCIAL_AUTH_GITLAB_KEY',
|
||||||
@@ -229,3 +225,7 @@ if GITHUB_ELIGIBLE_SPONSORSHIPS:
|
|||||||
GITHUB_ELIGIBLE_SPONSORSHIPS = GITHUB_ELIGIBLE_SPONSORSHIPS.split(',')
|
GITHUB_ELIGIBLE_SPONSORSHIPS = GITHUB_ELIGIBLE_SPONSORSHIPS.split(',')
|
||||||
else:
|
else:
|
||||||
GITHUB_ELIGIBLE_SPONSORSHIPS = []
|
GITHUB_ELIGIBLE_SPONSORSHIPS = []
|
||||||
|
|
||||||
|
|
||||||
|
if FRONTEND_URL:
|
||||||
|
CORS_ALLOWED_ORIGINS = [FRONTEND_URL]
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from .app.urls import urlpatterns
|
from django.views.static import serve
|
||||||
|
from .app.urls import urlpatterns as app_urlpatterns
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(urlpatterns)),
|
path('', include(app_urlpatterns)),
|
||||||
path('api/1/auth/social/', include('social_django.urls', namespace='social')),
|
path('api/1/auth/social/', include('social_django.urls', namespace='social')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
path(f'^{settings.STATIC_URL}<path:path>', serve, kwargs={
|
||||||
|
'document_root': settings.STATIC_ROOT,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
@@ -1,12 +1,6 @@
|
|||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
||||||
|
|
||||||
const htmlPluginOptions = {
|
|
||||||
hash: true,
|
|
||||||
minify: false
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: process.env.DEV ? 'development' : 'production',
|
mode: process.env.DEV ? 'development' : 'production',
|
||||||
context: __dirname,
|
context: __dirname,
|
||||||
@@ -61,17 +55,5 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new MiniCssExtractPlugin(),
|
new MiniCssExtractPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: './src/index.html',
|
|
||||||
filename: 'index.html',
|
|
||||||
chunks: ['index'],
|
|
||||||
...htmlPluginOptions,
|
|
||||||
}),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: './src/terminal.html',
|
|
||||||
filename: 'terminal.html',
|
|
||||||
chunks: ['terminal'],
|
|
||||||
...htmlPluginOptions,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
}
|
}
|
@@ -1,7 +1,20 @@
|
|||||||
const baseConfig = require('./webpack.base.config.js')
|
const baseConfig = require('./webpack.config.base.js')
|
||||||
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { AngularWebpackPlugin } = require('@ngtools/webpack')
|
const { AngularWebpackPlugin } = require('@ngtools/webpack')
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
|
const htmlPluginOptions = {
|
||||||
|
hash: true,
|
||||||
|
minify: false
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputPath = path.join(__dirname, 'build')
|
||||||
|
const backendURL = process.env.BACKEND_URL
|
||||||
|
if (!backendURL) {
|
||||||
|
throw new Error('BACKEND_URL env var is required')
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'browser',
|
name: 'browser',
|
||||||
@@ -18,11 +31,32 @@ module.exports = {
|
|||||||
directTemplateLoading: false,
|
directTemplateLoading: false,
|
||||||
skipCodeGeneration: false,
|
skipCodeGeneration: false,
|
||||||
}),
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './src/index.html',
|
||||||
|
filename: 'index.html',
|
||||||
|
chunks: ['index'],
|
||||||
|
...htmlPluginOptions,
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './src/terminal.html',
|
||||||
|
filename: 'terminal.html',
|
||||||
|
chunks: ['terminal'],
|
||||||
|
...htmlPluginOptions,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
apply: (compiler) => {
|
||||||
|
compiler.hooks.afterEmit.tap('AfterEmitPlugin', _ => {
|
||||||
|
fs.writeFileSync(path.join(outputPath, 'config.json'), JSON.stringify({
|
||||||
|
backendURL,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'build'),
|
path: outputPath,
|
||||||
pathinfo: true,
|
pathinfo: true,
|
||||||
publicPath: '/static/',
|
publicPath: '/',
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
chunkFilename: '[name].bundle.js',
|
chunkFilename: '[name].bundle.js',
|
||||||
},
|
},
|
||||||
|
39
webpack.config.server.js
Normal file
39
webpack.config.server.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const baseConfig = require('./webpack.config.base.js')
|
||||||
|
const path = require('path')
|
||||||
|
const { AngularWebpackPlugin } = require('@ngtools/webpack')
|
||||||
|
const nodeExternals = require('webpack-node-externals')
|
||||||
|
|
||||||
|
const outputPath = path.join(__dirname, 'build-server')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'server',
|
||||||
|
target: 'node',
|
||||||
|
...baseConfig,
|
||||||
|
entry: {
|
||||||
|
// 'index.server': path.resolve(__dirname, 'src/index.server.ts'),
|
||||||
|
'server': path.resolve(__dirname, 'src/server.ts'),
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
...baseConfig.resolve,
|
||||||
|
mainFields: ['esm2015', 'module', 'main'],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
...baseConfig.plugins,
|
||||||
|
new AngularWebpackPlugin({
|
||||||
|
entryModule: path.resolve(__dirname, 'src/app.server.module#AppServerModule'),
|
||||||
|
mainPath: path.resolve(__dirname, 'src/server.ts'),
|
||||||
|
tsconfig: 'tsconfig.json',
|
||||||
|
directTemplateLoading: false,
|
||||||
|
platform: 1,
|
||||||
|
skipCodeGeneration: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
// libraryTarget: 'commonjs',
|
||||||
|
path: outputPath,
|
||||||
|
pathinfo: true,
|
||||||
|
publicPath: '/',
|
||||||
|
filename: '[name].js',
|
||||||
|
chunkFilename: '[name].bundle.js',
|
||||||
|
},
|
||||||
|
}
|
@@ -1,32 +0,0 @@
|
|||||||
const baseConfig = require('./webpack.base.config.js')
|
|
||||||
const path = require('path')
|
|
||||||
const { AngularWebpackPlugin } = require('@ngtools/webpack')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'server',
|
|
||||||
target: 'node',
|
|
||||||
...baseConfig,
|
|
||||||
entry: {
|
|
||||||
'index.server': path.resolve(__dirname, 'src/index.server.ts'),
|
|
||||||
'server': path.resolve(__dirname, 'src/server.ts'),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
...baseConfig.plugins,
|
|
||||||
new AngularWebpackPlugin({
|
|
||||||
entryModule: path.resolve(__dirname, 'src/app/app.server.module`#AppServerModule'),
|
|
||||||
mainPath: path.resolve(__dirname, 'src/index.server.ts'),
|
|
||||||
tsconfig: 'tsconfig.json',
|
|
||||||
directTemplateLoading: false,
|
|
||||||
platform: 1,
|
|
||||||
skipCodeGeneration: false,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
libraryTarget: 'commonjs',
|
|
||||||
path: path.join(__dirname, 'build-server'),
|
|
||||||
pathinfo: true,
|
|
||||||
publicPath: '/static/',
|
|
||||||
filename: '[name].js',
|
|
||||||
chunkFilename: '[name].bundle.js',
|
|
||||||
},
|
|
||||||
}
|
|
Reference in New Issue
Block a user