- 嗨,开发人员!*命令:=〉跨环境NODE_ENV =生产节点服务器. mjs
错误
node:internal/errors:464
ErrorCaptureStackTrace(err);
^
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /home/windows/Documents/workspace/{projectPath}/dist/client/ssr-manifest.json
at new NodeError (node:internal/errors:371:5)
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:87:11)
at defaultGetFormat (node:internal/modules/esm/get_format:102:38)
at defaultLoad (node:internal/modules/esm/load:21:14)
at ESMLoader.load (node:internal/modules/esm/loader:359:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:58)
at new ModuleJob (node:internal/modules/esm/module_job:66:26)
at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:297:17)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:261:34)
at async Promise.all (index 0) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
我的配置:
- 第3.x.x版
- typescript
- 版本4.x.x
- 版本3.2.x
- 使用vite进行服务器端渲染
我做到了
- entry-server.js
- entry-client.ts
- server.js
正在发生什么
- "dev":"节点服务器. mjs",==〉工作正常
- "build":"npm运行构建:客户端&& npm运行构建:服务器",=〉工作正常
- "serve":"跨环境NODE_ENV =生产节点服务器. mjs",=〉错误。
请帮助我解决此问题。
我的服务器. mjs文件
// @ts-check
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import express from 'express';
const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD;
export async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === 'production',
hmrPort
) {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const resolve = (p) => path.resolve(__dirname, p);
const indexProd = isProd ? fs.readFileSync(resolve('dist/client/index.html'), 'utf-8') : '';
const manifest = isProd
? // @ts-ignore
(await import('./dist/client/ssr-manifest.json')).default
: {};
const app = express();
/**
* @type {import('vite').ViteDevServer}
*/
let vite;
if (!isProd) {
vite = await (
await import('vite')
).createServer({
base: '/',
root,
logLevel: isTest ? 'error' : 'info',
server: {
middlewareMode: true,
watch: {
// During tests we edit the files too fast and sometimes chokidar
// misses change events, so enforce polling for consistency
usePolling: true,
interval: 100,
},
hmr: {
port: hmrPort,
},
},
appType: 'custom',
});
// use vite's connect instance as middleware
app.use(vite.middlewares);
} else {
app.use((await import('compression')).default());
app.use(
'/test/',
(await import('serve-static')).default(resolve('dist/client'), {
index: false,
})
);
}
app.use('*', async (req, res) => {
try {
const url = req.originalUrl.replace('/test/', '/');
let template, render;
if (!isProd) {
// always read fresh template in dev
template = fs.readFileSync(resolve('index.html'), 'utf-8');
template = await vite.transformIndexHtml(url, template);
render = (await vite.ssrLoadModule('/src/entry-server.js')).render;
} else {
template = indexProd;
// @ts-ignore
render = (await import('./dist/server/entry-server.js')).render;
}
const [appHtml, preloadLinks] = await render(url, manifest);
const html = template
.replace(`<!--preload-links-->`, preloadLinks)
.replace(`<!--app-html-->`, appHtml);
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
} catch (e) {
vite && vite.ssrFixStacktrace(e);
console.log(e.stack);
res.status(500).end(e.stack);
}
});
return { app, vite };
}
if (!isTest) {
createServer().then(({ app }) =>
app.listen(4400, () => {
console.log('http://localhost:4400');
})
);
}
这是我的视频配置
/* import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
});
*/
import path from 'node:path';
import type { UserConfig } from 'vite';
import vuePlugin from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { fileURLToPath, URL } from 'node:url';
const virtualFile = '@virtual-file';
const virtualId = '\0' + virtualFile;
const nestedVirtualFile = '@nested-virtual-file';
const nestedVirtualId = '\0' + nestedVirtualFile;
const base = '/';
// preserve this to test loading __filename & __dirname in ESM as Vite polyfills them.
// if Vite incorrectly load this file, node.js would error out.
globalThis.__vite_test_filename = __filename;
globalThis.__vite_test_dirname = __dirname;
export default ({ command, ssrBuild }) => {
const config: UserConfig = {
base,
plugins: [
vuePlugin(),
vueJsx(),
{
name: 'virtual',
resolveId(id) {
if (id === '@foo') {
return id;
}
},
load(id, options) {
const ssrFromOptions = options?.ssr ?? false;
if (id === '@foo') {
// Force a mismatch error if ssrBuild is different from ssrFromOptions
return `export default { msg: '${
command === 'build' && !!ssrBuild !== ssrFromOptions
? `defineConfig ssrBuild !== ssr from load options`
: 'hi'
}' }`;
}
},
},
{
name: 'virtual-module',
resolveId(id) {
if (id === virtualFile) {
return virtualId;
} else if (id === nestedVirtualFile) {
return nestedVirtualId;
}
},
load(id) {
if (id === virtualId) {
return `export { msg } from "@nested-virtual-file";`;
} else if (id === nestedVirtualId) {
return `export const msg = "[success] from conventional virtual file"`;
}
},
},
// Example of a plugin that injects a helper from a virtual module that can
// be used in renderBuiltUrl
(function () {
const queryRE = /\?.*$/s;
const hashRE = /#.*$/s;
const cleanUrl = (url: string) => url.replace(hashRE, '').replace(queryRE, '');
let config;
const virtualId = '\0virtual:ssr-vue-built-url';
return {
name: 'built-url',
enforce: 'post',
configResolved(_config) {
config = _config;
},
resolveId(id) {
if (id === virtualId) {
return id;
}
},
load(id) {
if (id === virtualId) {
return {
code: `export const __ssr_vue_processAssetPath = (url) => '${base}' + url`,
moduleSideEffects: 'no-treeshake',
};
}
},
transform(code, id) {
const cleanId = cleanUrl(id);
if (
config.build.ssr &&
(cleanId.endsWith('.js') || cleanId.endsWith('.vue')) &&
!code.includes('__ssr_vue_processAssetPath')
) {
return {
code:
`import { __ssr_vue_processAssetPath } from '${virtualId}';__ssr_vue_processAssetPath;` +
code,
sourcemap: null, // no sourcemap support to speed up CI
};
}
},
};
})(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
experimental: {
renderBuiltUrl(filename, { hostType, type, ssr }) {
if (ssr && type === 'asset' && hostType === 'js') {
return {
runtime: `__ssr_vue_processAssetPath(${JSON.stringify(filename)})`,
};
}
},
},
build: {
minify: false,
},
ssr: {
noExternal: [
// this package has uncompiled .vue files
'example-external-component',
],
},
optimizeDeps: {
exclude: ['example-external-component'],
},
};
return config;
};
我所尝试的
我添加了cross-env NODE_ENV=production node --experimental-json-modules server.js
但我得到了另一种类型的错误。
错误
node:internal/errors:464
ErrorCaptureStackTrace(err);
^
TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///home/windows/Documents/workspace/{projectPath}/dist/client/ssr-manifest.json" needs an import assertion of type "json"
at new NodeError (node:internal/errors:371:5)
at validateAssertions (node:internal/modules/esm/assert:82:15)
at defaultLoad (node:internal/modules/esm/load:24:3)
at ESMLoader.load (node:internal/modules/esm/loader:359:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:58)
at new ModuleJob (node:internal/modules/esm/module_job:66:26)
at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:297:17)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:261:34)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:337:24) {
code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING'
}
1条答案
按热度按时间kknvjkwl1#
当我尝试为我的服务器导入一个JSON时,我也遇到了同样的错误。
需要类型为“json”的导入Assert
我决定:
在json.file中使用此函数,节点将重新识别导入。
另一个例子: