Flask 项目中使用 Svelte
如果想在新项目中同时使用 Flask 后端和 Svelte 前端,可以通过 flask-svelte 进行创建。而对于已有项目,在不重构 Flask 项目目录结构的前提下,可以按照本文的方法集成 Svelte 前端。
假设现有的 Flask 项目目录结构如下:
/home/user/my-project/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ ├── templates/
│ │ └── index.html
│ └── static/
│ └── style.css
├── tests/
│ └── test_app.py
├── venv/
├── setup.py
└── MANIFEST.in
在 my-project 下创建一个名为 frontend 的 Svelte 前端项目:
shellnpx degit sveltejs/template frontend
其目录结构如下:
/home/user/my-project/frontend/
├── public/
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── scripts/
│ └── setupTypeScript.js
├── src/
│ ├── App.svelte
│ └── main.js
├── package.json
├── README.md
└── rollup.config.js
如果执行命令:
shellnode scripts/setupTypeScript.js
将项目转换为使用 TypeScript 语言,则目录结构如下:
/home/user/my-project/frontend/
├── public/
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── src/
│ ├── App.svelte
│ ├── global.d.ts
│ └── main.ts
├── package.json
├── README.md
├── rollup.config.js
├── svelte.config.js
└── tsconfig.json
将 my-project/frontend/public/ 下的文件复制到 my-project/static 下,得到的项目目录结构如下:
/home/user/my-project/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ ├── templates/
│ │ └── index.html
│ └── static/
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── frontend/
│ ├── src/
│ │ ├── App.svelte
│ │ ├── global.d.ts
│ │ └── main.ts
│ ├── package.json
│ ├── README.md
│ ├── rollup.config.js
│ ├── svelte.config.js
│ └── tsconfig.json
├── tests/
│ └── test_app.py
├── venv/
├── setup.py
└── MANIFEST.in
Svelte 项目需要修改的文件有 tsconfig.json、rollup.config.js 和 package.json。修改内容见下面代码的高亮部分:
json{
"extends": "@tsconfig/svelte/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules/*", "__sapper__/*", "../static/*"]
}
javascriptimport { spawn } from 'child_process';
import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import css from 'rollup-plugin-css-only';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: '../static/build/bundle.js'
},
plugins: [
svelte({
preprocess: sveltePreprocess({ sourceMap: !production }),
compilerOptions: {
// enable run-time checks when not in production
dev: !production
}
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
exportConditions: ['svelte']
}),
commonjs(),
typescript({
sourceMap: !production,
inlineSources: !production
}),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('../static'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
json{
"name": "svelte-app",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv ../static --no-clear",
"check": "svelte-check"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-terser": "^0.4.0",
"rollup": "^3.15.0",
"rollup-plugin-css-only": "^4.3.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.1.2",
"svelte": "^3.55.0",
"svelte-check": "^3.0.0",
"svelte-preprocess": "^5.0.0",
"@rollup/plugin-typescript": "^11.0.0",
"typescript": "^4.9.0",
"tslib": "^2.5.0",
"@tsconfig/svelte": "^3.0.0"
},
"dependencies": {
"sirv-cli": "^2.0.0"
}
}
此外,由于 Flask 项目默认的静态资源路径 static_url_path
是 /static,为了兼容 Svelte,需要添加如下代码:
pythonimport app
from flask import send_from_directory
@app.route('/<path:path>')
@app.route('/', defaults={'path': 'index.html'})
def static_file(path):
return send_from_directory(app.static_folder, path)
也可以使用模板来渲染主页:
pythonimport app
from flask import send_from_directory, render_template
@app.route('/<path:path>')
def static_file(path):
return send_from_directory(app.static_folder, path)
@app.route('/')
def index():
return render_template('index.html')