Skip to content

Commit 4976652

Browse files
authored
Merge pull request #13 from newcore-network/fix/hotfix-external-config
Fix/hotfix external config
2 parents 6b4fc10 + 5d81fa0 commit 4976652

13 files changed

Lines changed: 180 additions & 91 deletions

File tree

RELEASE.md

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,7 @@
1-
## OpenCore CLI v1.3.0
1+
## OpenCore CLI v1.3.1
22

3-
### Summary
3+
### Fix
4+
- Fixed explicit resources build config issue
45

5-
- Views now use a single shared Vite configuration by default, with a minimal `vanilla` fallback for simple HTML/JS/TS UIs.
6-
- The CLI now exposes a public `createOpenCoreViteConfig` helper through `@open-core/cli/vite` so project-level Vite configs stay small and consistent.
7-
- PostCSS is auto-resolved from the OpenCore project root when present, which keeps Tailwind and older Chromium targets like RageMP CEF working without extra wiring.
8-
- Legacy framework-specific CLI view builders were removed. React, Vue, Svelte, and Astro should now be configured in Vite, not in the CLI.
9-
- Build path normalization and explicit-resource resolution were fixed so duplicated resource builds and stale overrides no longer happen when paths are written with or without `./`.
10-
11-
### Recommended Setup
12-
13-
- Keep a shared root Vite config next to `opencore.config.ts`.
14-
- Use `@open-core/cli/vite` to keep that config small.
15-
- Use `views.framework: 'vite'` for React, Vue, Svelte, Astro, Tailwind, PostCSS, Sass, or any advanced UI setup.
16-
- Use `views.framework: 'vanilla'` only for simple HTML/CSS/JS/TS views.
17-
- Add PostCSS only when your project needs it, such as older embedded browsers like RageMP CEF.
18-
19-
### Breaking Change
20-
21-
- Existing configs using `views.framework: 'react'`, `'vue'`, `'svelte'`, or `'astro'` must be updated to `views.framework: 'vite'`.
22-
- If those legacy framework values are still used, the CLI now fails with a clear migration error.
6+
### Improve
7+
- Improved entrypoint init templates, reduced and more elegant using `loggers` const

internal/builder/builder.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ func buildSideValue(enabled bool, cfg *config.BuildSideConfig) SideConfigValue {
122122
return SideConfigValue{Enabled: true, Options: buildSideOptionsFromConfig(cfg)}
123123
}
124124

125+
func buildResourceSideValue(side *config.ResourceBuildSideConfig, base *config.BuildSideConfig) SideConfigValue {
126+
if side == nil {
127+
return buildSideValue(true, base)
128+
}
129+
if !side.Enabled {
130+
return SideConfigValue{Enabled: false, Options: nil}
131+
}
132+
return buildSideValue(true, mergeBuildSideConfig(base, side.Options))
133+
}
134+
125135
func New(cfg *config.Config) *Builder {
126136
return &Builder{
127137
config: cfg,
@@ -797,10 +807,10 @@ func (b *Builder) collectAllTasks() []BuildTask {
797807
}
798808
if explicit.Build != nil {
799809
if explicit.Build.Server != nil {
800-
task.Options.Server = buildSideValue(*explicit.Build.Server, b.config.Build.Server)
810+
task.Options.Server = buildResourceSideValue(explicit.Build.Server, b.config.Build.Server)
801811
}
802812
if explicit.Build.Client != nil {
803-
task.Options.Client = buildSideValue(*explicit.Build.Client, b.config.Build.Client)
813+
task.Options.Client = buildResourceSideValue(explicit.Build.Client, b.config.Build.Client)
804814
}
805815
if explicit.Build.NUI != nil {
806816
task.Options.NUI = *explicit.Build.NUI
@@ -927,10 +937,10 @@ func (b *Builder) collectAllTasks() []BuildTask {
927937

928938
if res.Build != nil {
929939
if res.Build.Server != nil {
930-
task.Options.Server = buildSideValue(*res.Build.Server, b.config.Build.Server)
940+
task.Options.Server = buildResourceSideValue(res.Build.Server, b.config.Build.Server)
931941
}
932942
if res.Build.Client != nil {
933-
task.Options.Client = buildSideValue(*res.Build.Client, b.config.Build.Client)
943+
task.Options.Client = buildResourceSideValue(res.Build.Client, b.config.Build.Client)
934944
}
935945
if res.Build.NUI != nil {
936946
task.Options.NUI = *res.Build.NUI

internal/builder/builder_test.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ func TestCollectAllTasks_ExplicitResourceViewsInheritResourceDefaults(t *testing
686686
}
687687

688688
func TestCollectAllTasks_BuildOptions(t *testing.T) {
689-
serverFalse := false
689+
serverFalse := &config.ResourceBuildSideConfig{Enabled: false}
690690

691691
cfg := &config.Config{
692692
Name: "test-project",
@@ -701,7 +701,7 @@ func TestCollectAllTasks_BuildOptions(t *testing.T) {
701701
{
702702
Path: "./resources/client-only",
703703
Build: &config.ResourceBuildConfig{
704-
Server: &serverFalse,
704+
Server: serverFalse,
705705
},
706706
},
707707
},
@@ -751,6 +751,68 @@ func TestCollectAllTasks_BuildOptions(t *testing.T) {
751751
}
752752
}
753753

754+
func TestCollectAllTasks_ResourceSideOverrides(t *testing.T) {
755+
cfg := &config.Config{
756+
Name: "test-project",
757+
Destination: "./dist",
758+
OutDir: "./dist",
759+
Core: config.CoreConfig{
760+
Path: "./core",
761+
ResourceName: "[core]",
762+
},
763+
Resources: config.ResourcesConfig{
764+
Explicit: []config.ExplicitResource{
765+
{
766+
Path: "./resources/database",
767+
Build: &config.ResourceBuildConfig{
768+
Server: &config.ResourceBuildSideConfig{
769+
Enabled: true,
770+
Options: &config.BuildSideConfig{
771+
External: []string{"pg", "typeorm"},
772+
},
773+
},
774+
},
775+
},
776+
},
777+
},
778+
Build: config.BuildConfig{
779+
Server: &config.BuildSideConfig{Target: "node14"},
780+
Client: &config.BuildSideConfig{Target: "ES2020"},
781+
},
782+
}
783+
784+
builder := New(cfg)
785+
tasks := builder.collectAllTasks()
786+
787+
var databaseTask *BuildTask
788+
for i := range tasks {
789+
if tasks[i].Path == "./resources/database" {
790+
databaseTask = &tasks[i]
791+
break
792+
}
793+
}
794+
795+
if databaseTask == nil {
796+
t.Fatal("Expected database task")
797+
}
798+
799+
if !databaseTask.Options.Server.Enabled {
800+
t.Fatal("Expected Server to be enabled")
801+
}
802+
if databaseTask.Options.Server.Options == nil {
803+
t.Fatal("Expected Server options to be present")
804+
}
805+
if databaseTask.Options.Server.Options.Target != "node14" {
806+
t.Errorf("Expected server target 'node14', got '%s'", databaseTask.Options.Server.Options.Target)
807+
}
808+
if len(databaseTask.Options.Server.Options.External) != 2 {
809+
t.Fatalf("Expected 2 server externals, got %d", len(databaseTask.Options.Server.Options.External))
810+
}
811+
if databaseTask.Options.Server.Options.External[0] != "pg" || databaseTask.Options.Server.Options.External[1] != "typeorm" {
812+
t.Errorf("Expected server externals [pg typeorm], got %#v", databaseTask.Options.Server.Options.External)
813+
}
814+
}
815+
754816
func TestCollectAllTasks_RageMPLayout(t *testing.T) {
755817
cfg := &config.Config{
756818
Name: "test-project",

internal/config/config.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,38 @@ type ExplicitResource struct {
289289
}
290290

291291
type ResourceBuildConfig struct {
292-
Server *bool `json:"server,omitempty"`
293-
Client *bool `json:"client,omitempty"`
294-
NUI *bool `json:"nui,omitempty"`
295-
Minify *bool `json:"minify,omitempty"`
296-
SourceMaps *bool `json:"sourceMaps,omitempty"`
297-
ServerBinaries []string `json:"serverBinaries,omitempty"`
298-
ServerBinaryPlatform string `json:"serverBinaryPlatform,omitempty"`
299-
LogLevel string `json:"logLevel,omitempty"`
292+
Server *ResourceBuildSideConfig `json:"server,omitempty"`
293+
Client *ResourceBuildSideConfig `json:"client,omitempty"`
294+
NUI *bool `json:"nui,omitempty"`
295+
Minify *bool `json:"minify,omitempty"`
296+
SourceMaps *bool `json:"sourceMaps,omitempty"`
297+
ServerBinaries []string `json:"serverBinaries,omitempty"`
298+
ServerBinaryPlatform string `json:"serverBinaryPlatform,omitempty"`
299+
LogLevel string `json:"logLevel,omitempty"`
300+
}
301+
302+
type ResourceBuildSideConfig struct {
303+
Enabled bool
304+
Options *BuildSideConfig
305+
}
306+
307+
func (s *ResourceBuildSideConfig) UnmarshalJSON(data []byte) error {
308+
var enabled bool
309+
if err := json.Unmarshal(data, &enabled); err == nil {
310+
s.Enabled = enabled
311+
s.Options = nil
312+
return nil
313+
}
314+
315+
var opts BuildSideConfig
316+
if err := json.Unmarshal(data, &opts); err != nil {
317+
return err
318+
}
319+
320+
// An object means the side is enabled with per-resource overrides.
321+
s.Enabled = true
322+
s.Options = &opts
323+
return nil
300324
}
301325

302326
type StandaloneConfig struct {

internal/config/config_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ func TestConfigParsing(t *testing.T) {
6060
{
6161
"path": "./resources/admin",
6262
"resourceName": "admin-panel",
63+
"build": {
64+
"server": {
65+
"external": ["pg", "typeorm"],
66+
"target": "node20"
67+
}
68+
},
6369
"customCompiler": "./scripts/admin-build.js"
6470
}
6571
]
@@ -175,6 +181,21 @@ func TestConfigParsing(t *testing.T) {
175181
if res.CustomCompiler != "./scripts/admin-build.js" {
176182
t.Errorf("Expected resource customCompiler './scripts/admin-build.js', got '%s'", res.CustomCompiler)
177183
}
184+
if res.Build == nil || res.Build.Server == nil {
185+
t.Fatal("Expected resource build server override to be set")
186+
}
187+
if !res.Build.Server.Enabled {
188+
t.Fatal("Expected resource build server override to be enabled")
189+
}
190+
if res.Build.Server.Options == nil {
191+
t.Fatal("Expected resource build server options to be set")
192+
}
193+
if res.Build.Server.Options.Target != "node20" {
194+
t.Errorf("Expected resource build server target 'node20', got '%s'", res.Build.Server.Options.Target)
195+
}
196+
if len(res.Build.Server.Options.External) != 2 || res.Build.Server.Options.External[0] != "pg" || res.Build.Server.Options.External[1] != "typeorm" {
197+
t.Errorf("Expected resource build server externals [pg typeorm], got %#v", res.Build.Server.Options.External)
198+
}
178199
}
179200

180201
// Test standalone config
@@ -215,6 +236,19 @@ func TestConfigParsing(t *testing.T) {
215236
}
216237
}
217238

239+
func TestResourceBuildSideConfigUnmarshalBool(t *testing.T) {
240+
var side ResourceBuildSideConfig
241+
if err := json.Unmarshal([]byte(`false`), &side); err != nil {
242+
t.Fatalf("Failed to parse bool side config: %v", err)
243+
}
244+
if side.Enabled {
245+
t.Fatal("Expected side config to be disabled")
246+
}
247+
if side.Options != nil {
248+
t.Fatal("Expected side config options to be nil")
249+
}
250+
}
251+
218252
func TestRuntimeKindRageMP(t *testing.T) {
219253
cfg := &Config{
220254
Adapter: &AdapterConfig{
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import { Client } from '@open-core/framework/client';
1+
import { loggers } from '@open-core/framework'
2+
import { Client } from '@open-core/framework/client'
23

34
// Bootstrap the resource client
4-
Client.init({
5-
mode: 'RESOURCE',
6-
}).catch( (error: unknown) => {
7-
console.error(error)
8-
}).then(()=> {
9-
console.log('{{.ResourceName}} client initialized!')
10-
})
11-
12-
console.log('{{.ResourceName}} client loaded');
13-
5+
Client.init({ mode: 'RESOURCE' })
6+
.catch((e: unknown) => loggers.bootstrap.error('Error found', { error: e }))
7+
.then(() => loggers.bootstrap.info('Client initialized!'))
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import { Server } from '@open-core/framework/server';
1+
import { loggers } from '@open-core/framework'
2+
import { Server } from '@open-core/framework/server'
23

34
// Bootstrap the resource server
4-
Server.init({
5-
mode: 'RESOURCE',
6-
coreResourceName: 'core',
7-
}).catch( (error: unknown) => {
8-
console.error(error)
9-
}).then(()=> {
10-
console.log('{{.ResourceName}} server initialized!')
11-
})
5+
Server.init({ mode: 'RESOURCE', coreResourceName: 'core' })
6+
.catch((e: unknown) => loggers.bootstrap.error('Error found', { error: e }))
7+
.then(() => loggers.bootstrap.info('Server initialized!'))
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import { Client } from '@open-core/framework/client';
1+
import { loggers } from '@open-core/framework'
2+
import { Client } from '@open-core/framework/client'
23

34
// Bootstrap the standalone client
4-
Client.init({
5-
mode: 'STANDALONE',
6-
}).catch( (error: unknown) => {
7-
console.error(error)
8-
}).then(()=> {
9-
console.log('[{{.StandaloneName}}] Client initialized in STANDALONE mode');
10-
});
11-
12-
// Your client logic here
5+
Client.init({ mode: 'STANDALONE' })
6+
.catch((e: unknown) => loggers.bootstrap.error('Error found', { error: e }))
7+
.then(() => loggers.bootstrap.info('Client initialized!'))
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
// {{.StandaloneName}} - Server Side
2-
import { Server } from '@open-core/framework/server';
2+
import { loggers } from '@open-core/framework'
3+
import { init } from '@open-core/framework/server'
34

45
// Bootstrap the standalone server
56
// Standalone mode enables guards and decorators without depending on a core resource
6-
Server.init({
7-
mode: 'STANDALONE',
8-
}).catch( (error: unknown) => {
9-
console.error(error)
10-
}).then(()=> {
11-
console.log('[{{.StandaloneName}}] Server initialized in STANDALONE mode');
12-
});
13-
14-
// Your server logic here
7+
init({ mode: 'STANDALONE' })
8+
.catch((e: unknown) => loggers.bootstrap.error('Error found', { error: e }))
9+
.then(() => loggers.bootstrap.info('Server initialized!'))
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
// OpenCore Framework - Client Entry Point
2-
import { Client } from '@open-core/framework/client';
2+
import { loggers } from '@open-core/framework'
3+
import { Client } from '@open-core/framework/client'
34

45
// OpenCore scans decorators automatically when is Marked as Controller(), if not, import here
56
// Example: import './my-feature.client';
67

7-
Client.init({
8-
mode: 'CORE'
9-
}).catch( (error: unknown) => {
10-
console.error(error)
11-
}).then(()=> {
12-
console.log('{{.ProjectName}} client initialized!')
13-
})
8+
Client.init({ mode: 'CORE' })
9+
.catch((e: unknown) => loggers.bootstrap.error('Error found', { error: e }))
10+
.then(() => loggers.bootstrap.info('Client initialized!'))

0 commit comments

Comments
 (0)