从零做一个 InnoCMS 主题:目录结构、Blade 继承、SCSS 编译、Hook 集成
把 InnoCMS 装上跑起来后,企业官网的第二步永远是「让网站长得像我们自己」。默认主题是演示用的,不是生产用的。这篇文章把"从零开始做一个企业官网主题"的完整流程拆开讲:目录结构、Blade 继承、SCSS 设计 token、独立的资源编译、Hook 集成点。读完你能复制 themes/aurora/ 改一个新主题出来上线。
如果你只是想深度理解已有主题而不是从零写,建议先看 《Aurora 主题深度解析》。本文聚焦"动手做一个"而不是"分析一个"。
主题到底是什么
InnoCMS 的主题不是"皮肤",而是前台所有可见部分的完整接管。一个主题包含:
- HTML 结构(Blade 模板)
- 样式(SCSS 编译成 CSS)
- 脚本(JS 文件)
- 静态资源(图片、字体、favicon)
- 主题级翻译文件(覆盖 innopacks/front 的默认文案)
- 演示数据(首次安装时 seed 进数据库)
切换主题 = 改一个配置项 + 重编译资源,整个站点的视觉和行为完全变化。这就是为什么 InnoCMS 不需要"主题切换插件"——主题本身就是一等公民。
目录结构
所有主题放在 themes/<code>/ 下,目录名就是主题 code(小写、kebab-case)。标准结构:
themes/your-brand/
├── config.json # 主题元信息(必填)
├── views/ # Blade 模板
│ ├── layouts/
│ │ └── app.blade.php # 根布局(HTML/head/nav/footer)
│ ├── home.blade.php # 首页
│ ├── articles/
│ │ ├── index.blade.php # 文章列表
│ │ └── show.blade.php # 文章详情
│ ├── catalogs/
│ ├── pages/
│ ├── tags/
│ └── errors/
├── assets/
│ ├── scss/ # SCSS 源码
│ │ ├── abstracts/ # 变量、mixin、function
│ │ ├── base/ # reset、排版
│ │ ├── layout/ # 网格、容器
│ │ ├── sections/ # header、footer、nav
│ │ ├── pages/ # 各页面专属样式
│ │ └── utilities/ # 工具类
│ ├── js/ # 前端脚本
│ └── images/ # 主题静态图片
├── public/ # 编译输出(gitignore)
├── lang/ # 主题级翻译
└── demo/ # 演示数据
config.json:主题的身份证
{
"code": "your-brand",
"name": "Your Brand Theme",
"version": "1.0.0",
"author": "Your Team",
"description": "Enterprise corporate site theme",
"thumbnail": "thumbnail.png"
}
这个文件决定后台「主题管理」列表里怎么显示。code 必须跟目录名完全一致,否则加载时报错。
Blade 继承:三层结构
所有具体页面(home / articles / pages)都继承自 layouts/app.blade.php。根布局提供整页骨架:
<!-- themes/your-brand/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="{{ locale_code() }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ $page_title ?? setting('system_name') }}</title>
@yield('meta')
<link rel="stylesheet" href="{{ theme_asset('css/app.css') }}">
@hookinsert('layouts.header.assets')
</head>
<body>
@include('layouts.partials.header')
@yield('content')
@include('layouts.partials.footer')
@hookinsert('layouts.footer.assets')
</body>
</html>
具体页面只填 @section('content'):
<!-- themes/your-brand/views/articles/show.blade.php -->
@extends('layouts.app')
@section('meta')
<meta name="description" content="{{ $article->translation->meta_description }}">
@endsection
@section('content')
<article class="article-detail">
<h1>{{ $article->translation->title }}</h1>
{!! $article->translation->content !!}
</article>
@endsection
关键技巧:在根布局里预留 @hookinsert('layouts.header.assets') 和 @hookinsert('layouts.footer.assets'),让插件可以注入自己的 CSS/JS,而不需要改主题文件。
SCSS 设计 Token:可维护性的根基
所有视觉变量集中在 assets/scss/abstracts/_variables.scss,用 CSS 自定义属性暴露给运行时:
// assets/scss/abstracts/_variables.scss
:root {
--brand-primary: #0EA5E9; // 品牌主色
--brand-cta: #F97316; // CTA 强调色
--text-heading: #082F49;
--text-body: #475569;
--bg: #FFFFFF;
--bg-alt: #F8FAFC;
--border: #E2E8F0;
--radius-lg: 20px;
--shadow: 0 4px 12px rgba(12,74,110,.06);
--transition: .25s cubic-bezier(.4,0,.2,1);
}
组件 SCSS 引用这些变量而不是硬编码颜色。改 --brand-primary 一个值,全站按钮、链接、高亮、icon 全跟着变。这是「换主题色只需要一行」的实现基础。
资源编译:THEME 环境变量是关键
这是新主题作者踩过最隐蔽的坑。npm run prod 编译的是 InnoCMS 默认 front 资源,不会编译主题目录里的 SCSS。主题编译必须带 THEME 环境变量:
THEME=your-brand npm run build
这条命令扫描 themes/your-brand/assets/,把 SCSS 编译成 CSS 输出到 themes/your-brand/public/css/app.css。Blade 模板通过 theme_asset('css/app.css') 引用,自动带 ?v={timestamp} 缓存破坏。
常见踩坑:改完 SCSS 发现页面没变化,第一步永远是 ls -la themes/your-brand/public/css/app.css 看 mtime 是不是刚刚 —— HTTP 200 完全不能说明 CSS 更新了。
主题级翻译
每个主题可以有自己的翻译文件,覆盖 innopacks/front 的默认文案。结构:
themes/your-brand/lang/
└── zh-cn/
└── front.php
// themes/your-brand/lang/zh-cn/front.php
return [
'read_more' => '阅读全文',
'subscribe' => '订阅更新',
'contact_sales' => '联系销售',
];
Blade 里用 {{ theme_trans('front.read_more') }} 调用。如果主题没有这条 key,自动 fallback 到 innopacks/front 的默认翻译。
演示数据:第一次安装的种子
主题的 demo/ 目录可以放演示用的文章、单页、设置数据。后台「主题管理」点「导入演示数据」时,系统会把这些内容 seed 到数据库,让用户开箱看到一个"丰满"的演示站。
themes/your-brand/demo/
├── articles.json # 文章列表
├── pages.json # 单页列表
├── settings.json # 主题设置覆盖
└── images/ # 演示图片
最佳实践:演示数据用 picsum.photos 占位图(https://picsum.photos/seed/<unique>/1400/900),不要打包真实图片,让主题包保持小体积。
从零到上线的完整流程
- 复制
themes/aurora/改名themes/your-brand/ - 改
config.json的 code/name/version/author - 改
assets/scss/abstracts/_variables.scss里的--brand-primary和--brand-cta两个值 - 改
views/layouts/app.blade.php里的 logo 和 footer 文案 THEME=your-brand npm run build编译资源- 后台「主题管理」激活 your-brand
这套流程从开始到企业官网可访问,平均 4 小时 —— 这就是 InnoCMS 主题系统设计的回报。后续文章会拆 hook 系统和插件开发,把"二次开发"这条路彻底打通。