@transclude/create 0.1.0
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/LICENSE +21 -0
- package/index.js +197 -0
- package/package.json +34 -0
- package/templates/blank/README.md +19 -0
- package/templates/blank/_gitignore +6 -0
- package/templates/blank/app/routes/index.html +4 -0
- package/templates/blank/app/styles/global.css +10 -0
- package/templates/blank/jsconfig.json +11 -0
- package/templates/blank/package.json +19 -0
- package/templates/blank/transclude.config.js +27 -0
- package/templates/blank/vite.config.js +8 -0
- package/templates/minimal/README.md +20 -0
- package/templates/minimal/_gitignore +6 -0
- package/templates/minimal/app/public/robots.txt +2 -0
- package/templates/minimal/app/routes/404.html +4 -0
- package/templates/minimal/app/routes/_layout.html +16 -0
- package/templates/minimal/app/routes/about.html +4 -0
- package/templates/minimal/app/routes/index.html +4 -0
- package/templates/minimal/app/styles/global.css +24 -0
- package/templates/minimal/jsconfig.json +11 -0
- package/templates/minimal/package.json +19 -0
- package/templates/minimal/transclude.config.js +27 -0
- package/templates/minimal/vite.config.js +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joe Dakroub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/index.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Starts a project. `npm create transclude my-app`, or `npx create-transclude`.
|
|
3
|
+
//
|
|
4
|
+
// It copies a template and rewrites three things: the package name, the
|
|
5
|
+
// dependency on this framework, and the title on the page. Nothing else is
|
|
6
|
+
// generated, so what lands is what is in `templates/`, and reading that
|
|
7
|
+
// directory tells you exactly what a new project is.
|
|
8
|
+
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import readline from 'node:readline/promises';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
|
|
14
|
+
// `fileURLToPath`, never `url.pathname`: a space in the path stays
|
|
15
|
+
// percent-encoded in the second one, and `Atelier%20Dakroub` is not a directory.
|
|
16
|
+
const root = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const templates = path.join(root, 'templates');
|
|
18
|
+
|
|
19
|
+
const TEMPLATES = [
|
|
20
|
+
{ name: 'minimal', what: 'a layout, two pages, a 404 and a stylesheet' },
|
|
21
|
+
{ name: 'blank', what: 'one page, and nothing else' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/** npm refuses some of what a directory name allows, and so does this. */
|
|
25
|
+
const NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
26
|
+
|
|
27
|
+
function usage() {
|
|
28
|
+
const list = TEMPLATES.map((t) => ` ${t.name.padEnd(9)} ${t.what}`).join('\n');
|
|
29
|
+
return [
|
|
30
|
+
'Usage: create-transclude [directory] [options]',
|
|
31
|
+
'',
|
|
32
|
+
' --template <name> which files to start from',
|
|
33
|
+
`${list}`,
|
|
34
|
+
' --yes take the defaults and ask nothing',
|
|
35
|
+
' --link depend on a local checkout, for working on the framework',
|
|
36
|
+
'',
|
|
37
|
+
].join('\n');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Arguments, in the shape the rest of the file wants them. */
|
|
41
|
+
function parse(argv) {
|
|
42
|
+
const options = { dir: null, template: null, yes: false, link: false };
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
45
|
+
const arg = argv[i];
|
|
46
|
+
if (arg === '--yes' || arg === '-y') options.yes = true;
|
|
47
|
+
else if (arg === '--link') options.link = true;
|
|
48
|
+
else if (arg === '--help' || arg === '-h') options.help = true;
|
|
49
|
+
else if (arg === '--template' || arg === '-t') options.template = argv[++i];
|
|
50
|
+
else if (arg.startsWith('--template=')) options.template = arg.slice('--template='.length);
|
|
51
|
+
else if (arg.startsWith('-')) throw new Error(`unknown option ${arg}`);
|
|
52
|
+
else if (options.dir === null) options.dir = arg;
|
|
53
|
+
else throw new Error(`unexpected argument ${arg}`);
|
|
54
|
+
}
|
|
55
|
+
return options;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Every file under `dir`, relative to it.
|
|
60
|
+
*
|
|
61
|
+
* `node_modules` and `dist` are skipped so running this from a directory that
|
|
62
|
+
* was used once does not copy a build into a new project.
|
|
63
|
+
*/
|
|
64
|
+
function walk(dir, base = dir, out = []) {
|
|
65
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
66
|
+
if (entry.name === 'node_modules' || entry.name === 'dist') continue;
|
|
67
|
+
const full = path.join(dir, entry.name);
|
|
68
|
+
if (entry.isDirectory()) walk(full, base, out);
|
|
69
|
+
else out.push(path.relative(base, full));
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* What a directory can be written into.
|
|
76
|
+
*
|
|
77
|
+
* An existing directory is fine when it holds nothing that would be
|
|
78
|
+
* overwritten; a `.git` from `git init` is the ordinary case. Anything else is
|
|
79
|
+
* refused rather than merged, because a half-copied project is worse to
|
|
80
|
+
* untangle than one that never started.
|
|
81
|
+
*/
|
|
82
|
+
function checkTarget(dir) {
|
|
83
|
+
if (!fs.existsSync(dir)) return;
|
|
84
|
+
const held = fs.readdirSync(dir).filter((name) => name !== '.git' && name !== '.DS_Store');
|
|
85
|
+
if (held.length) {
|
|
86
|
+
throw new Error(`${path.relative(process.cwd(), dir) || '.'} is not empty`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What a new project declares.
|
|
92
|
+
*
|
|
93
|
+
* `--link` points at a checkout of the framework, which is the only way to try
|
|
94
|
+
* an unpublished one: the version below is this package's, and the two are
|
|
95
|
+
* released together.
|
|
96
|
+
*/
|
|
97
|
+
function dependency(link) {
|
|
98
|
+
if (link) return `file:${path.resolve(root, '..')}`;
|
|
99
|
+
const { version } = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
100
|
+
return `^${version}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function ask(options) {
|
|
104
|
+
// A pipe is not a person. Without a terminal the defaults are the only answers
|
|
105
|
+
// available, and hanging on a prompt nobody can see is the worse failure.
|
|
106
|
+
if (options.yes || !process.stdin.isTTY) {
|
|
107
|
+
return { dir: options.dir ?? 'my-app', template: options.template ?? TEMPLATES[0].name };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
111
|
+
try {
|
|
112
|
+
let dir = options.dir;
|
|
113
|
+
while (!dir) dir = (await rl.question('Directory (my-app): ')).trim() || 'my-app';
|
|
114
|
+
|
|
115
|
+
let template = options.template;
|
|
116
|
+
if (!template) {
|
|
117
|
+
const names = TEMPLATES.map((t) => t.name).join(', ');
|
|
118
|
+
const answer = (await rl.question(`Template (${names}) [minimal]: `)).trim();
|
|
119
|
+
template = answer || TEMPLATES[0].name;
|
|
120
|
+
}
|
|
121
|
+
return { dir, template };
|
|
122
|
+
} finally {
|
|
123
|
+
rl.close();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Copies one template, substituting the two placeholders.
|
|
129
|
+
*
|
|
130
|
+
* Only `.json`, `.js`, `.html`, `.css` and `.md` are read as text. Anything else
|
|
131
|
+
* is copied byte for byte, so a template may hold an image without this
|
|
132
|
+
* corrupting it.
|
|
133
|
+
*/
|
|
134
|
+
function copy(from, to, replacements) {
|
|
135
|
+
const TEXT = new Set(['.json', '.js', '.html', '.css', '.md', '.txt']);
|
|
136
|
+
|
|
137
|
+
for (const rel of walk(from)) {
|
|
138
|
+
// `.gitignore` in a template would be applied to the template itself by
|
|
139
|
+
// every tool that reads one, including npm when this is packed.
|
|
140
|
+
const target = path.join(to, rel === '_gitignore' ? '.gitignore' : rel);
|
|
141
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
142
|
+
|
|
143
|
+
if (!TEXT.has(path.extname(rel))) {
|
|
144
|
+
fs.copyFileSync(path.join(from, rel), target);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let text = fs.readFileSync(path.join(from, rel), 'utf8');
|
|
149
|
+
for (const [token, value] of Object.entries(replacements)) {
|
|
150
|
+
text = text.split(token).join(value);
|
|
151
|
+
}
|
|
152
|
+
fs.writeFileSync(target, text);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function main() {
|
|
157
|
+
const options = parse(process.argv.slice(2));
|
|
158
|
+
if (options.help) {
|
|
159
|
+
process.stdout.write(usage());
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const answers = await ask(options);
|
|
164
|
+
const template = TEMPLATES.find((t) => t.name === answers.template);
|
|
165
|
+
if (!template) {
|
|
166
|
+
const names = TEMPLATES.map((t) => t.name).join(', ');
|
|
167
|
+
throw new Error(`no template called ${JSON.stringify(answers.template)}. There is ${names}.`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const target = path.resolve(process.cwd(), answers.dir);
|
|
171
|
+
checkTarget(target);
|
|
172
|
+
|
|
173
|
+
const name = path.basename(target);
|
|
174
|
+
if (!NAME.test(name)) {
|
|
175
|
+
throw new Error(`${JSON.stringify(name)} is not a usable package name`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
copy(path.join(templates, template.name), target, {
|
|
179
|
+
__NAME__: name,
|
|
180
|
+
__TRANSCLUDE__: dependency(options.link),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const where = path.relative(process.cwd(), target);
|
|
184
|
+
process.stdout.write(
|
|
185
|
+
[
|
|
186
|
+
`\nCreated ${name} from the ${template.name} template.\n\n`,
|
|
187
|
+
where ? ` cd ${where}\n` : '',
|
|
188
|
+
' npm install\n',
|
|
189
|
+
' npm run dev\n\n',
|
|
190
|
+
].join(''),
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main().catch((error) => {
|
|
195
|
+
process.stderr.write(`\n${error.message}\n\n${usage()}`);
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@transclude/create",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Starts a transclude project. `npm create @transclude my-app`.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"transclude",
|
|
7
|
+
"scaffold",
|
|
8
|
+
"starter",
|
|
9
|
+
"create"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://transclude.dev",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/transclude-dev/transclude.git",
|
|
15
|
+
"directory": "create"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/transclude-dev/transclude/issues"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Joe Dakroub",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"create-transclude": "./index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"index.js",
|
|
31
|
+
"templates",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# __NAME__
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
npm install
|
|
5
|
+
npm run dev
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
A page is an `.html` file in `app/routes/`. The directory tree is the route
|
|
9
|
+
table, so `app/routes/about.html` answers `/about`.
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `npm run dev` | the dev server, with hot reload |
|
|
14
|
+
| `npm run check` | types, from the shapes your loaders return |
|
|
15
|
+
| `npm run preview` | build, then serve the build |
|
|
16
|
+
| `npm run build` | write `dist/` |
|
|
17
|
+
|
|
18
|
+
`dist/static` is self-contained: any static host will serve it. Everything that
|
|
19
|
+
reads a request is served by `npm start`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* Linked by every page. It goes through Vite, so nesting and @import work, and
|
|
2
|
+
the build hashes and compresses it. */
|
|
3
|
+
|
|
4
|
+
body {
|
|
5
|
+
margin: 0 auto;
|
|
6
|
+
padding: 2rem 1rem;
|
|
7
|
+
max-width: 42rem;
|
|
8
|
+
font: 16px/1.6 system-ui, sans-serif;
|
|
9
|
+
color-scheme: light dark;
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "node --env-file-if-exists=.env node_modules/.bin/transclude-dev",
|
|
7
|
+
"build": "transclude-build",
|
|
8
|
+
"start": "node --env-file-if-exists=.env node_modules/.bin/transclude-serve",
|
|
9
|
+
"preview": "npm run build && npm start",
|
|
10
|
+
"check": "transclude-check"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@transclude/core": "__TRANSCLUDE__"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.9",
|
|
17
|
+
"vite": "^8"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Every path the framework needs is here, relative to `appDir` unless it says
|
|
2
|
+
// otherwise. `npx transclude-check` reads this too.
|
|
3
|
+
//
|
|
4
|
+
// The keys left out have defaults, and the defaults are the quiet ones: no
|
|
5
|
+
// proxy, no feed, no sitemap, no service worker list, no script on any page.
|
|
6
|
+
// See the configuration page in the docs for the whole list.
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
appDir: 'app',
|
|
10
|
+
routesDir: 'routes',
|
|
11
|
+
elementsDir: 'elements',
|
|
12
|
+
stylesheet: 'app/styles/global.css',
|
|
13
|
+
|
|
14
|
+
// Dev and production both listen here, so this app has one port. `PORT` in the
|
|
15
|
+
// environment wins.
|
|
16
|
+
port: 1960,
|
|
17
|
+
|
|
18
|
+
// `never` redirects /about/ to /about with a 301, so a page has one URL.
|
|
19
|
+
trailingSlash: 'never',
|
|
20
|
+
|
|
21
|
+
// Signs cookies, which is what makes one usable as a session. Read it from the
|
|
22
|
+
// environment: this file is yours, so where the secret lives is your decision.
|
|
23
|
+
cookieSecret: globalThis.process?.env?.COOKIE_SECRET ?? null,
|
|
24
|
+
|
|
25
|
+
outDir: 'dist',
|
|
26
|
+
typesFile: 'app/transclude-env.d.ts',
|
|
27
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# __NAME__
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
npm install
|
|
5
|
+
npm run dev
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
A page is an `.html` file in `app/routes/`. The directory tree is the route
|
|
9
|
+
table, so `app/routes/about.html` answers `/about`. `_layout.html` wraps every
|
|
10
|
+
page beside it and below.
|
|
11
|
+
|
|
12
|
+
| | |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `npm run dev` | the dev server, with hot reload |
|
|
15
|
+
| `npm run check` | types, from the shapes your loaders return |
|
|
16
|
+
| `npm run preview` | build, then serve the build |
|
|
17
|
+
| `npm run build` | write `dist/` |
|
|
18
|
+
|
|
19
|
+
`dist/static` is self-contained: any static host will serve it. Everything that
|
|
20
|
+
reads a request is served by `npm start`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
// A layout wraps every page in its directory and below. This one takes the
|
|
3
|
+
// current path so it can mark the link you are on.
|
|
4
|
+
export default async ({ route }) => ({ path: route.path });
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<title>__NAME__</title>
|
|
8
|
+
|
|
9
|
+
<nav>
|
|
10
|
+
<a href="/" aria-current="${path === '/' ? 'page' : 'false'}">Home</a>
|
|
11
|
+
<a href="/about" aria-current="${path === '/about' ? 'page' : 'false'}">About</a>
|
|
12
|
+
</nav>
|
|
13
|
+
|
|
14
|
+
<!-- The page renders here. A layout with no <slot> is a warning, because
|
|
15
|
+
nothing inside it could appear. -->
|
|
16
|
+
<main><slot></slot></main>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* Linked by every page. It goes through Vite, so nesting and @import work, and
|
|
2
|
+
the build hashes and compresses it. */
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
--muted: #666;
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@media (prefers-color-scheme: dark) {
|
|
10
|
+
:root { --muted: #999; }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
margin: 0 auto;
|
|
15
|
+
padding: 2rem 1rem;
|
|
16
|
+
max-width: 42rem;
|
|
17
|
+
font: 16px/1.6 system-ui, sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
h1 { font-size: 1.6rem; margin: 0 0 1rem; }
|
|
21
|
+
a { color: inherit; }
|
|
22
|
+
|
|
23
|
+
nav { display: flex; gap: 1rem; margin-bottom: 2rem; }
|
|
24
|
+
nav a[aria-current='page'] { font-weight: 600; }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "node --env-file-if-exists=.env node_modules/.bin/transclude-dev",
|
|
7
|
+
"build": "transclude-build",
|
|
8
|
+
"start": "node --env-file-if-exists=.env node_modules/.bin/transclude-serve",
|
|
9
|
+
"preview": "npm run build && npm start",
|
|
10
|
+
"check": "transclude-check"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@transclude/core": "__TRANSCLUDE__"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.9",
|
|
17
|
+
"vite": "^8"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Every path the framework needs is here, relative to `appDir` unless it says
|
|
2
|
+
// otherwise. `npx transclude-check` reads this too.
|
|
3
|
+
//
|
|
4
|
+
// The keys left out have defaults, and the defaults are the quiet ones: no
|
|
5
|
+
// proxy, no feed, no sitemap, no service worker list, no script on any page.
|
|
6
|
+
// See the configuration page in the docs for the whole list.
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
appDir: 'app',
|
|
10
|
+
routesDir: 'routes',
|
|
11
|
+
elementsDir: 'elements',
|
|
12
|
+
stylesheet: 'app/styles/global.css',
|
|
13
|
+
|
|
14
|
+
// Dev and production both listen here, so this app has one port. `PORT` in the
|
|
15
|
+
// environment wins.
|
|
16
|
+
port: 1960,
|
|
17
|
+
|
|
18
|
+
// `never` redirects /about/ to /about with a 301, so a page has one URL.
|
|
19
|
+
trailingSlash: 'never',
|
|
20
|
+
|
|
21
|
+
// Signs cookies, which is what makes one usable as a session. Read it from the
|
|
22
|
+
// environment: this file is yours, so where the secret lives is your decision.
|
|
23
|
+
cookieSecret: globalThis.process?.env?.COOKIE_SECRET ?? null,
|
|
24
|
+
|
|
25
|
+
outDir: 'dist',
|
|
26
|
+
typesFile: 'app/transclude-env.d.ts',
|
|
27
|
+
};
|