# san-loader
**Repository Path**: mirrors_ecomfe/san-loader
## Basic Information
- **Project Name**: san-loader
- **Description**: San-Loader 是基于 webpack 的工具,允许开发者书写 San 单文件的方式来进行组件开发。
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-08
- **Last Updated**: 2026-02-07
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# San-Loader
San-Loader 是基于 webpack 的工具,允许开发者书写 San
单文件的方式来进行组件开发。
```html
Hello {{name}}!
```
San 单文件在写法上与 Vue 类似,San-Loader 会将 `template`、`script`、`style` 等标签块当中的内容和属性提取出来,并交给 webpack 分别进行处理。最终单文件对外返回的将是一个普通的 San 组件类,我们可以直接使用它进行 San 组件的各种操作:
```js
import App from './App.san';
let app = new App();
app.attach(document.body);
```
## 使用方法
通过 npm 进行 San-Loader 的安装:
```shell
npm install --save-dev san-loader
```
然后在 webpack 的配置文件上增加一条规则应用到 `.san` 文件上,并且增加一个 SanLoaderPlugin:
```js
const SanLoaderPlugin = require('san-loader/lib/plugin');
module.exports = {
// ...
module: {
rules: [
{
test: /\.san$/,
loader: 'san-loader'
}
// ...
]
},
plugins: [new SanLoaderPlugin()]
};
```
如前面提到,San-Loader 会将单文件的各个部分拆分出来,并交给其他的 Loader 来进行资源处理,因此还需要配置各个模块的处理方法,比如:
```js
const SanLoaderPlugin = require('san-loader/lib/plugin');
module.exports = {
// ...
module: {
rules: [
{
test: /\.san$/,
loader: 'san-loader'
},
{
test: /\.js$/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.html$/,
loader: 'html-loader'
}
// ...
]
},
plugins: [new SanLoaderPlugin()]
};
```
在默认情况下,`template`、`script`、`style` 会分别采用 `.html`、`.js`、`.css` 所对应的 Loader 配置进行处理,当然我们也可以在相应的标签上添加 `lang` 属性来指定不同的语言处理比如:
```html
```
这样,对应的样式模块就可以当成 `.less` 文件进行处理,只需要配置上相应的 Loader 即可。
```js
// ...
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
}
};
```
更加完整的 webpack 配置,可以参考示例:
- [San-Loader Webpack HMR 配置实例](https://github.com/ecomfe/san-loader/blob/master/examples/hmr/webpack.config.js)
- [San-Loader Webpack Minimal](https://github.com/ecomfe/san-loader/blob/master/examples/minimal/webpack.config.js)
## Options
| Name | Type | Default | Description |
| :---------------: | :------------------------: | :------: | :------------------------------------------------------------------------ |
| `compileTemplate` | {'none'|'aPack'|'aNode'} | `'none'` | 将组件的`template` 编译成`aPack`、`aNode`,**默认不编译**,详细见下面说明 |
| `esModule` | `{Boolean}` | `false` | san-loader 默认使用 CommonJS 模块语法来生成 JS 模块,将该参数设为 true 可以改用 ES 模块语法 |
| `autoAddScriptTag` | `{Boolean}` | `true` | `.san` 文件中不含 `script` 标签时自动添加,默认为`true` |
**特殊说明:**
> `compileTemplate`:San 组件的`string`类型的`template`通过编译可以返回[aNode](https://github.com/baidu/san/blob/master/doc/anode.md)结构,在定义组件的时候,可以直接使用`aNode`作为 template,这样可以减少了组件的`template`编译时间,提升了代码的执行效率,但是转成`aNode`的组件代码相对来说比较大,所以在`san@3.9.0`引入的概念的`aNode`压缩结构`aPack`,**使用`aPack`可以兼顾体积和效率的问题**。san-loader 中的`compileTemplate`就是来指定要不要将组件编译为`aPack`/`aNode`。**如果只想,单文件使用`compileTemplate`编译成对应的`aPack`或者`aNode`,可以直接在`template`上面写:``**。
> 使用 `pug` 等预处理模版语言时,`compileTemplate` 不生效,请使用 [san-anode-loader](https://github.com/vanishcode/san-anode-loader)
### 扩展阅读
- [aNode 结构设计](https://github.com/baidu/san/blob/master/doc/anode.md)
- [aPack: aNode 压缩结构设计](https://github.com/baidu/san/blob/master/doc/anode-pack.md)
## 单文件写法
### template
单文件中 `template` 模块的主要作用是提供一种更为便捷的方式来书写组件的 template 字符串。在配置 webpack 的时候,需要对 template 部分配置 raw-loader、html-loader 等等。其中如果 template 当中需要使用到图片、字体文件,建议采用 html-loader 配合 url-loader 的形式完成相关配置。例如:
```html
```
则需要在 webpack 配置文件当中增加如下配置:
```js
module.exports = {
module: {
rules: [
// ...
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.png$/,
loader: 'url-loader'
}
]
}
};
```
template 部分可以省略不写,直接在 script 模块当中定义也是可以的:
```html
```
template 模块也支持通过 src 标签引入 template 文件:
```html
```
> 注意:html-loader 最新版本在生产环境([production](https://github.com/webpack-contrib/html-loader/blob/master/src/index.js#L38-L41))会默认开启`minimize=true`,会导致 san 解析 template 失败,所以使用 html-loader 的时候建议开启`minimize=false`。
### script
script 模块必须通过 `export default` 将组件的 JS 代码导出。在写法上,支持类似 Vue 的写法:
```html
```
San-Loader 会自动为导出为普通对象的模块外部自动包上 `san.defineComponent` 使之成为真正的 San 组件。
```js
import script from './App.san?san&type=script&lang=js';
import san from 'san';
// ...
export default san.defineComponent(script);
```
我们也可以通过 class 的方式:
```html
```
也可以配合 san-store 一起使用,比如:
```html
```
总之在写法上与普通的 San 组件不存在太大区别,区别的地方只在于 template 和 style 的部分可以放到别的模块里进行书写。
当组件不依赖数据和计算的时候,script 块可以省略不写。
与 template 相似,script 模块也可以通过定义 src 属性导入相应的组件代码:
```html
```
在默认情况下,script 模块的内容会被当成 `.js` 文件进行处理,如改成 TypeScript 的话,可以通过在 script 标签上添加属性 `lang="ts"` 将该模块标记为 `.ts` 文件,然后自行在 webpack 配置文件当中添加对 `.ts` 文件的处理 Loader 即可:
```html
```
这时候需要修改`ts-loader`配置:
```js
{
test: /\.ts$/,
loader: 'ts-loader',
options: { appendTsSuffixTo: [/\.san$/] }
}
```
或者`babel-loader`的配置:
```js
{
test: /\.ts$/,
use: [
{
loader: 'babel-loader',
options: {
plugins: [
require.resolve('@babel/plugin-proposal-class-properties'),
require.resolve('san-hot-loader/lib/babel-plugin')
],
presets: [
[
require.resolve('@babel/preset-env'),
{
targets: {
browsers: '> 1%, last 2 versions'
},
modules: false
}
],
// 下面配置 allExtensions
[require.resolve('@babel/preset-typescript'), {allExtensions: true}]
]
}
}
]
}
```
### style
style 模块用来书写组件的样式,在用法上与 template、script 类似,例如:
```html
```
在默认情况下,style 模块的内容会被当成 `.css` 文件处理,我们可以通过修改 `lang` 属性来指定文件类型。同时与 template、script 存在区别的地方在于,style 模块允许写多个,因此下面写的 style 模块都是有效的,全都会作用到当前的组件上:
```html
```
## CSS Modules
### 基本使用
[CSS Modules][css-modules] 是一个流行的用于模块化和组合 CSS 的系统,san-loader 提供了与 css-loader 的集成以支持 CSS Modules 的特性。在模板中可以这样写:
```html
```
如果要对所有文件生效,在上面的 webpack 配置示例中给 css-loader 添加 `modules` 参数即可。例如:
```javascript
// webpack.config.js 省略上下文
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]_[hash:base64:5]'
},
localsConvention: 'camelCase',
sourceMap: true
}
}
]
}
];
```
其中 `localIdentName` 用来指定编译后的类名,在开发环境请使用 `'[hash:base64]'`;
`localsConvention` 是在模板和 JavaScript 中引用的名称,默认是不转换,`'camelCase'` 是把类名转换为驼峰风格。详情请参考:[css-loader 文档][css-loader]。
### 命名 CSS Modules
默认通过``方式添加的样式,在组件中会给`data`添加`$style`变量。如果组件中有多个`style`,想区分不同的 style,也可以通过命名的方式定义不同`style`的变量名,示例如下:
``` html
```
### 允许非 CSS Modules
也可以指定部分 style 标签使用 CSS Modules,其他仍然是普通的全局 CSS:
```html
```
san-loader 会给带 `module` 的 `
```
也可以设置子组件的根元素样式(会被正确编译到随机类名):
```html
```
但父组件无法覆盖子组件的内部类的样式,比如子组件内存在类名 `.foo`,父组件里的 `.child .foo` 不会渗透进入子组件:
```html
```
但除类名之外的元素名、ID 等会渗透进入子组件,例如下面的 `.child span` 会作用于 `` 里的 ``:
```html
```
[css-modules]: https://github.com/css-modules/css-modules
[css-loader]: https://github.com/webpack-contrib/css-loader#localsconvention
## Scoped CSS(version 0.3.0 以上)
你可以在 `
```
浏览器中会表现为
```html
...
normal black
...
red
```