内容
- 概览
- 简单的HTML文件
- 使用静态服务器
- 标准的JavaScript项目
概览
每个软件项目都有其特定的需求。这些需求中的许多可以通过一些工具来解决:webpack
、gulp
、CSS
预处理器、打包器、转译器等。
正因为如此,通常不是简单地就能开始一个项目。一些框架提供了他们自己的工具来帮助解决这个问题。但然后,你必须集成并学习这些应用程序是如何工作的。
Owl被设计为不需要任何工具即可使用。正因为如此,Owl可以“轻松”地集成到现代构建工具链中。在这一部分,我们将讨论几种不同的设置来启动一个项目。每种设置在不同情况下都有优点和缺点。
简单的HTML文件
最简单的设置如下:一个包含你代码的简单JavaScript文件。为此,让我们创建以下文件结构:
hello_owl/
index.html
owl.js
app.js
文件owl.js可以从github.com/odoo/owl/re…发布的最新版本中下载。它是一个单独的JavaScript文件,将所有Owl导出到全局owl对象中。注意有多个文件,这种情况下,我们需要一个以.iife
结尾的文件:它们是为了直接在浏览器中使用而构建的。
现在,index.html应该包含以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello Owl</title>
<script src="owl.iife.js"></script>
</head>
<body>
<script src="app.js"></script>
</body>
</html>
app.js应该看起来像这样:
const { Component, mount, xml } = owl;
// Owl组件
class Root extends Component {
static template = xml`<div>Hello Owl</div>`;
}
mount(Root, document.body);
现在,只需在浏览器中加载此HTML文件,应该就会显示一条欢迎消息。这个设置不花哨,但是非常简单。它不需要任何工具。它可以通过使用Owl的压缩版本进行轻微优化。
使用静态服务器
之前的设置有一个很大的缺点:应用程序代码位于一个单独的文件中。显然,我们可以将它分割成几个文件,并在HTML页面中添加多个
有一个低技术解决方案来解决这个问题:使用原生JavaScript模块。然而,这有一个要求:出于安全原因,浏览器不会接受通过文件协议提供的模块。这意味着我们需要使用静态服务器。
让我们以以下文件结构开始一个新项目:
hello_owl/
src/
index.html
main.js
owl.js
root.js
像以前一样,文件owl.js可以从github.com/odoo/owl/re…发布的最新版本中下载。注意有多个文件,这种情况下,我们需要一个以.iife
结尾的文件:它们是为了直接在浏览器中使用而构建的。
现在,index.html应该包含以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello Owl</title>
<script src="owl.iife.js"></script>
</head>
<body>
<script src="main.js" type="module"></script>
</body>
</html>
注意main.js脚本标签具有type="module"
属性。这意味着浏览器将解析脚本作为一个模块,并加载其所有依赖项。
这里是root.js和main.js的内容:
// root.js ----------------------------------------------------------------------
const { Component, mount, xml } = owl;
export class Root extends Component {
static template = xml`<div>Hello Owl</div>`;
}
// main.js ----------------------------------------------------------------------
const { mount } = owl;
import { Root } from "./root.js";
mount(Root, document.body);
main.js文件导入了root.js文件。注意import语句有一个.js后缀,这很重要。大多数文本编辑器可以理解此语法并提供自动完成。
现在,要执行此代码,我们需要静态地提供src文件夹。一个低技术的方法是使用例如python http.server
功能:
$ cd src
$ python -m http.server 8022 # 现在内容可在localhost:8022上获得
另一种更"javascript"的方式是创建一个npm应用程序。为此,我们可以在项目根目录下添加以下package.json文件:
{
"name": "hello_owl",
"version": "0.1.0",
"description": "启动Owl应用程序",
"main": "src/index.html",
"scripts": {
"serve": "serve src"
},
"author": "John",
"license": "ISC",
"devDependencies": {
"serve": "^11.3.0"
}
}
我们现在可以使用npm install命令安装serve工具,然后,使用简单的npm run serve命令启动静态服务器。
标准JavaScript项目
之前的设置有效,对于某些用例(包括快速原型设计)来说确实不错。然而,它缺少一些有用的功能,如实时重载、测试套件或将代码打包到一个文件中。
所有这些功能,以及许多其他功能,都可以通过许多不同的方式完成。由于配置这样的项目确实不是微不足道的,我们在这里提供一个示例,可以用作起点。
我们的标准Owl项目具有以下文件结构:
hello_owl/
public/
index.html
src/
components/
Root.js
main.js
tests/
components/
Root.test.js
helpers.js
.gitignore
package.json
webpack.config.js
此项目有一个public文件夹,旨在包含所有静态资源,如图像和样式。src文件夹有JavaScript源代码,最后,tests包含测试套件。
这里是index.html的内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello Owl</title>
</head>
<body>
</body>
</html>
注意这里没有
// src/components/Root.js -------------------------------------------------------
import { Component, xml, useState } from "@odoo/owl";
export class Root extends Component {
static template = xml`<div t-on-click="update">Hello <t t-esc="state.text"/></div>`;
state = useState({ text: "Owl" });
update() {
this.state.text = this.state.text === "Owl" ? "World" : "Owl";
}
}
// src/main.js -----------------------------------------------------------------
import { utils, mount } from "@odoo/owl";
import { Root } from "./components/Root";
mount(Root, document.body);
// tests/components/Root.test.js ------------------------------------------------
import { Root } from "../../src/components/Root";
import { makeTestFixture, nextTick, click } from "../helpers";
import { mount } from "@odoo/owl";
//------------------------------------------------------------------------------
// Setup
//------------------------------------------------------------------------------
let fixture;
beforeEach(() => {
fixture = makeTestFixture();
});
afterEach(() => {
fixture.remove();
});
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
describe("Root", () => {
test("按预期工作...", async () => {
await mount(Root, fixture);
expect(fixture.innerHTML).toBe("<div>Hello Owl</div>");
click(fixture, "div");
await nextTick();
expect(fixture.innerHTML).toBe("<div>Hello World</div>");
});
});
// tests/helpers.js ------------------------------------------------------------
import { Component } from "@odoo/owl";
import "regenerator-runtime/runtime";
export async function nextTick() {
await new Promise((resolve) => setTimeout(resolve));
await new Promise((resolve) => requestAnimationFrame(resolve));
}
export function makeTestFixture() {
let fixture = document.createElement("div");
document.body.appendChild(fixture);
return fixture;
}
export function click(elem, selector) {
elem.querySelector(selector).dispatchEvent(new Event("click"));
}
最后,这里是配置文件.gitignore、package.json和webpack.config.js:
node_modules/
package-lock.json
dist/
// package.json
{
"name": "hello_owl",
"version": "0.1.0",
"description": "Owl示例",
"main": "src/index.html",
"scripts": {
"test": "jest",
"build": "webpack --mode production",
"dev": "webpack-dev-server --mode development"
},
"author": "Jesse Chang",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"babel-jest": "^25.1.0",
"babel-loader": "^8.0.6",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"html-webpack-plugin": "^3.2.0",
"jest": "^25.1.0",
"regenerator-runtime": "^0.13.3",
"serve": "^11.3.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.2"
},
"dependencies": {
"@odoo/owl": "^2.2.10"
},
"babel": {
"plugins": ["@babel/plugin-proposal-class-properties"],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
},
"jest": {
"verbose": false,
"testRegex": "(/tests/.*(test|spec))\.js?$",
"moduleFileExtensions": ["js"],
"transform": {
"^.+\.[t|j]sx?$": "babel-jest"
}
}
}
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const host = process.env.HOST || "localhost";
module.exports = function (env, argv) {
const mode = argv.mode || "development";
return {
mode: mode,
entry: "./src/main.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".js", ".jsx"],
},
devServer: {
contentBase: path.resolve(__dirname, "public/index.html"),
compress: true,
hot: true,
host,
port: 3000,
publicPath: "/",
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: path.resolve(__dirname, "public/index.html"),
}),
],
};
};
通过此设置,我们现在可以使用以下脚本命令:
npm run build
# 在dist/中以生产模式构建完整应用程序
npm run dev
# 启动具有实时重载的开发服务器
npm run test
# 运行jest测试套件