Skip to content

Commit 6541705

Browse files
authored
Add build-time eval example (#9)
1 parent 41d1e4a commit 6541705

File tree

10 files changed

+192
-17
lines changed

10 files changed

+192
-17
lines changed

Package.swift

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import PackageDescription
2020
let package = Package(
2121
name: "pkl-swift-examples",
2222
platforms: [
23-
.macOS(.v13),
23+
.macOS(.v13)
2424
],
2525
dependencies: [
2626
.package(url: "https://github.com/vapor/vapor.git", from: "4.89.0"),
@@ -38,13 +38,36 @@ let package = Package(
3838
.product(name: "Vapor", package: "vapor"),
3939
]
4040
),
41-
.testTarget(name: "AppTests", dependencies: [
42-
"Gen",
43-
.target(name: "App"),
44-
.product(name: "XCTVapor", package: "vapor"),
41+
.executableTarget(
42+
name: "BuildTimeEval",
43+
dependencies: [
44+
"Gen",
45+
.product(name: "Vapor", package: "vapor"),
46+
.product(name: "PklSwift", package: "pkl-swift"),
47+
],
48+
resources: [
49+
.embedInCode("config.msgpack")
50+
]
51+
),
52+
.testTarget(
53+
name: "AppTests",
54+
dependencies: [
55+
"Gen",
56+
.target(name: "App"),
57+
.product(name: "XCTVapor", package: "vapor"),
58+
59+
// Workaround for https://github.com/apple/swift-package-manager/issues/6940
60+
.product(name: "Vapor", package: "vapor"),
61+
]),
62+
.testTarget(
63+
name: "BuildTimeEvalTests",
64+
dependencies: [
65+
"Gen",
66+
.target(name: "BuildTimeEval"),
67+
.product(name: "XCTVapor", package: "vapor"),
4568

46-
// Workaround for https://github.com/apple/swift-package-manager/issues/6940
47-
.product(name: "Vapor", package: "vapor"),
48-
]),
69+
// Workaround for https://github.com/apple/swift-package-manager/issues/6940
70+
.product(name: "Vapor", package: "vapor"),
71+
]),
4972
]
5073
)

README.adoc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ This is a basic HTTP server that is configured via Pkl in the `pkl/` directory.
66

77
== Requirements
88

9-
* Swift +5.9
10-
* Pkl +0.25.0
9+
* Swift +6.1
10+
* Pkl +0.30.0;s
1111

1212
== Project structure
1313

@@ -23,7 +23,10 @@ This is a basic HTTP server that is configured via Pkl in the `pkl/` directory.
2323
| Generated Swift sources from Pkl
2424

2525
| `Sources/App/`
26-
| Swift files
26+
| Swift files for runtime evaluation example
27+
28+
| `Sources/BuildTimeEval/`
29+
| Swift files for build-time evaluation example
2730
|===
2831

2932
== Codegen
@@ -45,6 +48,18 @@ With that installed, generate Swift sources via:
4548
pkl-gen-swift pkl/**.pkl -o Sources/Gen
4649
----
4750

51+
== Build-time evaluation
52+
53+
The example in `Sources/BuildTimeEval/` shows how the https://pkl-lang.org/main/current/bindings-specification/binary-encoding.html[`pkl-binary` encoding] can be used to configure applications.
54+
This mechanism separates evaluation of Pkl code from application runtime by encoding the configuration data as `pkl-binary`, storing it in a file, and loading it later during application startup.
55+
This example works identically to the runtime evaluation example, but does not require the application to spawn the Pkl CLI as a subprocess.
56+
57+
The configuration module is rendered as `pkl-binary` by running:
58+
[source,bash]
59+
----
60+
pkl eval pkl/dev/config.pkl -f pkl-binary -o pkl/dev/config.msgpack
61+
----
62+
4863
== Running the server
4964

50-
To run the project call `swift run`.
65+
To run the project call `swift run`.

Sources/BuildTimeEval/Controllers/.gitkeep

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
��Config�:file:///Users/jbasch/src/pkl-swift-examples/pkl/Config.pkl���hostname�localhost��port����tcpNoDelayÓ�backlog̀��serverName�Pkl Swift Example Server
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import Gen
18+
import PklSwift
19+
import Vapor
20+
21+
// configures your application
22+
public func configure(_ app: Application) async throws {
23+
let conf = try! PklDecoder.decode(Config.Module.self, from: PackageResources.config_msgpack)
24+
// configure with Pkl
25+
app.http.server.configuration.hostname = conf.hostname
26+
app.http.server.configuration.port = conf.port
27+
app.http.server.configuration.tcpNoDelay = conf.tcpNoDelay
28+
app.http.server.configuration.backlog = conf.backlog
29+
app.http.server.configuration.serverName = conf.serverName
30+
31+
// register routes
32+
try routes(app)
33+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import Logging
18+
import Vapor
19+
20+
@main
21+
enum Entrypoint {
22+
static func main() async throws {
23+
var env = try Environment.detect()
24+
try LoggingSystem.bootstrap(from: &env)
25+
26+
let app = Application(env)
27+
defer { app.shutdown() }
28+
29+
do {
30+
try await configure(app)
31+
} catch {
32+
app.logger.report(error: error)
33+
throw error
34+
}
35+
try await app.execute()
36+
}
37+
}

Sources/BuildTimeEval/routes.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import Vapor
18+
19+
func routes(_ app: Application) throws {
20+
app.get { _ async in
21+
"It works!"
22+
}
23+
24+
app.get("hello") { _ async -> String in
25+
"Hello, world!"
26+
}
27+
}

Tests/AppTests/AppTests.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@
1414
// limitations under the License.
1515
//===----------------------------------------------------------------------===//
1616

17-
@testable import App
1817
import XCTVapor
1918

19+
@testable import App
20+
2021
final class AppTests: XCTestCase {
2122
func testHelloWorld() async throws {
2223
let app = Application(.testing)
2324
defer { app.shutdown() }
2425
try await configure(app)
2526

26-
try app.test(.GET, "hello", afterResponse: { res in
27-
XCTAssertEqual(res.status, .ok)
28-
XCTAssertEqual(res.body.string, "Hello, world!")
29-
})
27+
try app.test(
28+
.GET, "hello",
29+
afterResponse: { res in
30+
XCTAssertEqual(res.status, .ok)
31+
XCTAssertEqual(res.body.string, "Hello, world!")
32+
})
3033
}
3134
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import XCTVapor
18+
19+
@testable import BuildTimeEval
20+
21+
final class BuildTimeEvalTests: XCTestCase {
22+
func testHelloWorld() async throws {
23+
let app = Application(.testing)
24+
defer { app.shutdown() }
25+
try await configure(app)
26+
27+
try app.test(
28+
.GET, "hello",
29+
afterResponse: { res in
30+
XCTAssertEqual(res.status, .ok)
31+
XCTAssertEqual(res.body.string, "Hello, world!")
32+
})
33+
}
34+
}

pkl/dev/config.pkl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
// limitations under the License.
1515
//===----------------------------------------------------------------------===//
1616

17+
// generate config.msgpack: pkl eval pkl/dev/config.pkl -f pkl-binary -o Sources/BuildTimeEval/config.msgpack
18+
1719
amends "../Config.pkl"
1820

1921
hostname = "localhost"

0 commit comments

Comments
 (0)