Omil
📝Webpack loader for Omi.js React.js and Rax.js components 基于 Omi.js,React.js 和 Rax.js 单文件组件的 Webpack 模块加载器
Install / Use
/learn @Wscats/OmilREADME
English | 简体中文
Omil 是什么?
omil是一个 webpack 的 loader,它允许你以一种名为单文件组件(SFCs)的格式撰写 Omi 组件:
<template lang="html" name="component-name">
<header onClick="${this.test}">${this.data.title}</header>
</template>
<script>
export default class {
test(){ console.log('Hello Eno!') }
install() {
this.data = { title: 'Omi' }
}
}
</script>
<style>
header { color: #58bc58; }
</style>
Omil 还提供了很多酷炫的特性:
- 允许为 Omi 组件的每个部分使用其它的 webpack loader,例如在
<style>的部分使用 Sass 和在<template>的部分使用 jsx; - 允许在一个 .omi 文件中使用自定义块,并对其运用自定义的 loader 链;
- 使用 webpack loader 将
<style>和<template>中引用的资源当作模块依赖来处理; - 在开发过程中使用热重载来保持状态。
简而言之,webpack 和 Omi Loader 的结合为你提供了一个现代、灵活且极其强大的前端工作流,来帮助撰写 Omi.js 应用。
起步
Omi CLI
如果你不想手动设置 webpack,我们推荐使用 Omi CLI 直接创建一个项目的脚手架。通过 Omi CLI 创建的项目会针对多数常见的开发需求进行预先配置,做到开箱即用。
如果Omi CLI提供的内建没有满足你的需求,或者你乐于从零开始创建你自己的 webpack 配置,那么请继续阅读这篇指南。
手动设置
安装
首先先安装好Omil
npm install -D omil
如果你使用的是 Visual Studio Code 进行开发,强烈建议下载 Omi Snippets 扩展,它会提供给你语法高亮,局部编译等功能。您可以在 VSC 扩展界面里面搜索 omi 这个关键词出现Omi Snippets点击安装即可,稍等片刻,当它安装成功后会提醒你需要重新加载编辑工具,点击重新加载即可使用。
每个Omil包的新版本发布时,一个相应版本的Omi Snippets也会随之发布。
webpack 配置
Omi Loader 的配置和其它的 loader 基本一样。
// webpack.config.js
module.exports = {
module: {
rules: [
// ... 其它规则
{
test: /\.omi|eno$/,
loader: 'omil'
}
]
}
}
一个更完整的 webpack 配置示例看起来像这样:
module.exports = {
mode: 'development',
module: {
rules: [{
test: /\.omi|eno$/,
use: [{
loader: require.resolve('omil'),
options: {
// Use in development, You should remove in production
sourceMaps: 'both',
// Config babel plugins for async, await and other many features
plugins: [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
}],
// Or you can use eno-loader or omil directly
// use: ['eno-loader']
// use: ['omil']
}]
}
}
Omi Snippets
在配置完 Omil 之后,我们可以在 VS Code 上同时安装好 Omi Snippets 扩展,这个插件可以方便的让你把 .omi 和 .eno 后缀文件在未经过 webpack 处理前转化为 .js 文件,让你可以直观了解到单文件组件经过 omil 转化后的 JS 文件内容,这相当于局部编译减轻 webpack 处理单文件时候的不必要消耗。
目录结构
例如你在 webpack 的入口文件夹中有一个 .omi 的后缀文件,当你新建并经过编辑保存之后,Omi Snippets扩展会在同级目录下新建一份同名但不同后缀的 .js 文件
- src
- Hello.omi
- Hello.js
|Hello.omi|开发中你需要编写的单文件组件|
|-|-|
|Hello.js|修改或者保存文件Hello.omi后经过插件转化的js文件|
如下图,左边的代码是我们编写的 .omi 后缀的单文件组件,右边是经过 Omi Snippets 生成的 .js 后缀文件。
<img src="https://wscats.github.io/omi-docs/public/images/transfer.png" />示例代码
上图的示例代码如下
<template>标签负责放 JSX 的内容,属性name="my-test"为该组件的名字,后面可以在 JSX 中用<my-text>使用该组件;<script>标签负责放入组件的逻辑文件,固定的结构为export default class { // 你的代码 }或者为export default HOC(class { // 你的代码 })两种形式,第一种是定义类组件,第二种用来定义高阶组件,你的代码部分可以放入生命周期,函数等;<style>标签负责定义该组件的局部样式
<template name="my-test">
<div class="example">
{ this.data.msg }
</div>
</template>
<script>
export default class {
install () {
this.data = {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
color: red;
}
</style>
以下代码就是经过 Omi Snippets 生成的 .js 后缀文件,可以用于在你没有 omil 模块下,主逻辑文件或者其他组件引入调用。
import { WeElement, define, h } from "omi";
class MyTest extends WeElement {
render() {
return h(
"div",
{
class: "example"
},
this.data.msg
);
}
install() {
this.data = {
msg: "Hello world!"
};
}
}
MyTest.css = `
.example {
color: red;
}
`;
define("my-test", MyTest);
配合 React 开发
安装 React 脚手架和一些必要模块。
npm install create-react-app
# 初始化项目
create-react-app my-project
# 进入项目文件夹目录
cd my-project
# 安装项目依赖
npm install
# 安装 styled-components 这个务必得安装 用于处理 React 单文件组件局部样式
npm install styled-components --save
# 安装 omil 处理React单文件组件,把 .omi 或者 .eno 后缀文件处理为 JS
npm install omil --save-dev
在配置完 Omil 之后,我们可以在 VS Code 上同时安装好 Omi Snippets 扩展,这个插件可以方便的让你把 .omi 和 .eno 后缀文件在未经过 webpack 处理前转化为 .js 文件,让你可以直观了解到单文件组件经过 omil 转化后的 JS 文件内容,这相当于局部编译减轻 webpack 处理单文件时候的不必要消耗。
编写第一个组件
现在你可以使用单文件组件来编写 React 组件,默认生成类组件。
- name属性值是组件名要满足 React 框架的组件名字定义规范,首字母必须大写字母;
<template>模板中不能有<script>和<style>代码片段。
<template name="Component-name">
<div>
<p>{this.state.title}</p>
</div>
</template>
<script>
export default class {
constructor(props) {
super(props)
this.state = {
title: "react"
}
}
componentDidMount(){
console.log('生命周期')
}
}
</script>
<style>
p {color: #58bc58};
</style>
以上文件经过 Omil 处理后将会转化为以下代码:
import { Component as WeElement, createElement as h } from "react";
import styled from "styled-components";
const StyledComponents = styled.div`
/* CSS */
p {
color: #58bc58;
}
`;
class ComponentName extends WeElement {
render() {
return h(
StyledComponents,
null,
h("div", null, h("p", null, this.state.title))
);
}
constructor(props) {
super(props);
this.state = {
title: "react"
};
}
componentDidMount() {
console.log("生命周期");
}
}
ComponentName.css = `
/* CSS */
p {color: #58bc58};
`;
export default ComponentName;
语言块规范
简介
.omi 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Omi 组件。每个 .omi 文件包含三种类型的顶级语言块 <template>、<script> 和 <style>:
<template name="my-test">
<div class="example">
{ this.data.msg }
</div>
</template>
<script>
export default class {
install () {
this.data = {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
color: red;
}
</style>
Omil 会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Omi.js 组件定义好的自定义标签对象。
Omil 支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 lang 属性。例如,你可以像下面这样使用 Sass 语法编写样式:
<style lang="sass">
/* write Sass! */
</style>
语言块
<template>模板
每个 .omi 文件最多包含一个 <template> 块。
内容将被提取,如果是 JSX 会编译为函数片段,如果为 html 会编译为字符串,并最终注入到从<script>导出的组件 render 函数中。
属性name = "xxx-xxx"(Omi组件)
定义name="xxx-xxx"可以给组件定义一个名字,这个名字会自动调用 omi 框架的 define('xxx-xxx', xxxXxx) 方法来注册组件,你就可以在页面中用这个属性名<xxx-xxx></xxx-xxx>来使用该组件
注意:
- name属性值是组件名要满足 omi 框架的组件名字定义规范,首字母不能用大写字母,并且中间必须有
-字符; <template>模板中不能有<script>和<style>代码片段。
<template name="my-test">
<div class="example">
{ this.data.msg }
</div>
</template>
在页面容器中如此使用
<my-test/>
<my-test></my-test>
属性name = "XxxXxx"(React组件)
定义name="XxxXxx"可以给组件定义一个名字,这个名字会自动调用 React 框架的 React.Component 方法来定义类组件,你就可以在页面中用这个属性名<XxxXxx></XxxXxx>来使用该组件
注意:
- name属性值是组件名要满足 React 框架的组件名字定义规范,首字母必须大写字母;
<template>模板中不能有<script>和<style>代码片段。
<template name="MyTest">
<div class="example">
{ this.data.msg }
</div>
</template>
在页面容器中如此使用
<MyTest/>
<MyTest></MyTest>
属性lang = "html"(仅支持Omi)
默认情况下,我们的<template>模板是使用 JSX 语法,如果我们增加属性lang = "html",就可以支持编写html格式的字符串模板,你可以使用 ES6 的语法来编写 html 模板<div>${ this.data.msg }<div>,Omil 和 Omi-Snippets 会自动帮你引入Omi.html()方法帮你在客户端进行处理,会有一定的性能损耗,一般情况下不建议使用。
<template name="my-test" lang="html">
<div class="example">
${ this.data.msg }
</div>
</template>
<script>脚本
每个 .omi 文件最多包含一个 <script> 块。
类组件
如果我们使用过 react 我们会了解到组件通常有两种定义方式,一种是函数组件,一种是类组件,Omil 默认是帮你创建类组件,我们在export default class { // 你的代码 }或者module.exports = class { // 你的代码 }片段中写入你的组件逻辑代码,
注意:
- 定义类组件必须是
export default class { // 你的代码 }这种写法,class MyText {} ; export default MyText这种写法不可以,因为 Omil 和 Omil Snippets 只识别连续的export default class这段字符串
|export default class { // 你的代码 }|可以|建议使用|
|-|-|-|
|module.exports = class { // 你的代码 }|可以|支持|
|class MyText { // 你的代码 }<br/>export default MyText|不可以|不支持|
|class MyText { // 你的代码 }<br/>module.export = MyText|不可以|不支持|
<script>
export default class {
install () {
this.data = {
msg: 'Hello world!'
}
}
}
</script>
高阶组件(仅支持React)
有时候我们可以使用高阶组件拓展组件本身的一些功能,高阶组件跟类组件一样,只支持下面规定的写法。
|export default HOC(class { // 你的代码 })|可以|建议使用|
|-|-|-|
|module.exports = HOC(class { // 你的代码 })|可以|支持|
|class MyText { // 你的代码 }<br/>export default HOC(MyText)|不可以|不支持|
|class MyText { // 你的代码 }<br/>module.export = HOC(MyText)|不可以|不支持|
<script>
export default HOC(class {
install () {
this.data = {
msg: 'Hello world!'
}
}
})
</script>
下面是一个高阶组件的详细参考例子
<template name="MyTest">
<div><p>{this.state.title}</p></div>
</template>
<script>
// 高阶函数
const HOC = (props) => {
return (WraooedComponent) => {
return class HOC extends WeElement {
render() {
return (<div><WraooedComponent name={{ ...this.props }} /></div>)
}
}
}
}
export default HOC({
age: 18
})(class {
install () {
this.data = {
msg: 'Hello world!'
}
}
})
</script>
<style lang="scss">
p { color: #58bc58; }
</style>
或者你可以这样写
<template name="MyTest">
{HOC(<div><p>{this.state.title}</p></div>)}
</template>
<script>
// 高阶函数
const HOC = (props) => {
return (WraooedComponent) => {
return class HOC extends WeElement {
render() {
return (<div><WraooedComponent name={{ ...this.props }} /></div>)
}
}
}
}
export default class {
install () {
this.data = {
msg: 'Hello world!'
}
}
}
</script>
<style lang="scss">
p { color: #58bc58;
Related Skills
bluebubbles
339.5kUse when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles".
node-connect
339.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
slack
339.5kUse when you need to control Slack from OpenClaw via the slack tool, including reacting to messages or pinning/unpinning items in Slack channels or DMs.
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
