# san-hot-loader **Repository Path**: mirrors_ecomfe/san-hot-loader ## Basic Information - **Project Name**: san-hot-loader - **Description**: San-Hot-Loader 为基于 Webpack 构建的 San 项目提供热更新功能。能够让 San 项目在调试开发的时候变得更加方便。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-15 - **Last Updated**: 2026-04-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # San-Hot-Loader San-Hot-Loader 为基于 Webpack 构建的 [San](https://github.com/baidu/san) 项目提供热更新功能。能够让 San 项目在调试开发的时候变得更加方便。 ## 安装 **代码1-1** ```shell $ npm install --save-dev san-hot-loader ``` ## 配置 您需要在 Webpack 配置文件当中添加 san-hot-loader 相关配置信息。完整的配置信息可参考示例项目当中的 [webpack.config.js](./examples/component-hmr/webpack.config.js) 配置,其中与 san-hot-loader 有关的配置如下所示: **代码2-1** ```js module.exports = { // ... 其他的 webpack 配置信息 module: { rules: [ { test: /\.js$/, use: ['san-hot-loader'] } // ... 其他的 loader 信息 ] } } ``` 这样,在启动 webpack 进行代码调试的时候,就自动实现了 San 组件与 San-Store 的热更新功能。 > **需要注意的是**,当项目代码使用了 ES7 及以上的语法时,通常需要 babel-loader 将代码进行转换成 ES5 语法,这个转换过程可能会带来额外的 Babel Helper、Polyfill 代码的注入,在这种情况下,san-hot-loader 同时也提供了 babel 插件来实现热更新代码注入: **代码2-2** ```js module.exports = { // ... 其他的 webpack 配置信息 module: { rules: [ { test: /\.js$/, use: [ // 'san-hot-loader', { loader: 'babel-loader', options: { plugins: [ // 通过 babel plugin 的形式添加 require.resolve('san-hot-loader/lib/babel-plugin') ] } } ] } // ... 其他的 loader 信息 ] } } ``` ## 使用 在默认情况下,san-hot-loader 自动开启对 San 组件与 San-Store 模块的热更新代码注入,通过自动检测的手段来判断哪些是 San 组件,哪些是 San-Store 模块。 ### San 组件格式 #### 常规 San 组件格式 一个简单的常规 San 组件文件如下所示: **代码3-1** ```js // app.js import san from 'san'; export default san.defineComponent({ template: '
Hello {{name}}
', initData: function () { return {name: 'San'}; } }); ``` 也可以采用 class 的方式: **代码3-2** ```js import {Component} from 'san'; export default class App extends Component { static template = 'Hello {{name}}
'; initData() { return {name: 'San'}; } } ``` 或者采用 ES5 Function Constructor 的方式来定义组件: **代码3-3** ```js var san = require('san'); function App(options) { san.Component(this, options); } san.inherits(App, san.Component); App.prototype.template = 'Hello {{name}}
'; App.prototype.initData = function () { return {name: 'San'}; }; module.exports = App; ``` 基于上述例子不难看出,一个功能完整的组件代码文件应包含以下特征: 1. 文件引入 `san` 模块(`import`、`require`); 2. 使用 `san` 模块所提供的 API(defineComponent、Component)定义组件; 3. 将定义好的组件作为默认模块导出(`export default`、`module.exports`); 以上就是 san-hot-loader 判断文件是否为普通 San 组件的方法。 #### 结合 San-Store 的组件写法 当项目使用 San-Store 时,根据相关文档的说明,需要使用 `san-store` 提供的 connect 方法将状态源与组件关联起来,如: **代码3-4** ```js import {defineComponent} from 'san'; import {connect} from 'san-store'; import './register-store-actions'; const App = defineComponent({ template: 'Hello {{name}}
', initData: function () { return {name: 'San'}; } }); // connect 到默认 store const NewApp = connect.san({name: 'name'})(App); export default NewApp; ``` 或者: **代码3-5** ```js import {defineComponent} from 'san'; import {connect} from 'san-store'; import store from './store'; const App = defineComponent({ template: 'Hello {{name}}
', initData: function () { return {name: 'San'}; } }); // connect 到自定义 store const connector = connect.createConnector(store); const NewApp = connector({name: 'name'})(App); export default NewApp; ``` 因此在这种情况下,san-hot-loader 对于满足以下特征的文件,也同样能够识别为 San 组件: 1. 文件引入 `san-store`(`import`、`require`); 2. 使用 `san-store` 提供的 `connect.san` 或 `connect.createConnector(store)` 得到的方法连接 store 与当前 San 组件获得新的组件; 3. 将得到的新组件作为默认模块导出(`export default`、`module.exports`); ### San-Store 模块写法 san-hot-loader 为 san-store 提供了 action 的热更新功能,即在修改 san-store 注册 action 的文件时,store 与组件所保存的状态都不会丢失,并且在触发 action 时自动使用最新的 action。 san-store 提供了默认 store 和自定义 store 两种,因此在支持 san-hot-loader 自动识别的写法上也存在不同。 #### 默认 store san-store 提供了默认 store 实例,在使用上可以通过 `import {store} from 'san-store'` 获取该实例对象,调用其 `addAction` 方法可以完成对默认 store 的 action 注册。 一个简单的对默认 store 实例注册 action 的代码如下所示: **代码3-6** ```js // register-store-actions.js import {store} from 'san-store'; import {builder} from 'san-update'; store.addAction('increase', function (num) { builder().set('num', num + 1); }); store.addAction('decrease', function (num) { builder().set('num', num - 1); }); ``` 这个文件会被 san-hot-loader 成功识别,并注入热更新代码。该文件可以参考前面的代码3-4 的方式引入到项目当中。 它应具有以下特征: 1. 文件引入 `san-store`; 2. 使用 `san-store` 提供的 store.addAction 方法注册 action; 3. 文件不存在任何模块导出(`export`、`export default`、`module.exports`、`exports.xxx`); 在这里需要解释一下特征 3。首先,在对默认 store 实例注册 action 之后,可以直接使用 `san-store` 提供的 `connect.san` 方法对 San 组件进行关联,因此无需对默认 store 实例做任何的模块导出;其次,热更新的本质是前端异步接收更新后的文件模块,并进行替换,在这里 san-hot-loader 只针对注册 action 的功能进行了替换处理,如果文件存在模块导出,san-hot-loader 无法去跟踪处理相应行为从而会导致热更新出错。所以要求文件不存在任何模块导出。 #### 自定义 store san-store 提供了自定义 store 的方法来满足开发者多 store 的状态管理需求。一个简单的自定义 store 代码如下所示: **代码3-7** ```js // store.js import {Store} from 'san-store'; import {builder} from 'san-update'; export default new Store({ initData: { num: 0 }, actions: { increase(num) { return builder().set('num', num + 1); }, decrease(num) { return builder().set('num', num - 1); } } }); ``` 通过类似前面代码3-5 的写法使用自定义 store,同样地,在修改自定义 store 文件时,同样也能够获得热更新效果。 需要注意的是,在这种自定义 Store 的情况下,只有在修改 `actions` 部分的代码会实现热更新,当 initData 部分出现改动时,则会直接进行页面重载。 自定义 store 的文件应具有以下特征: 1. 文件引入 `san-store`; 2. 使用 `san-store` 提供的 `Store` 方法实例化自定义 store; 3. 将自定义 store 以默认模块导出; ### 特殊注释 前面给出了符合 san-hot-loader 满足热更新自动检测的一些文件写法,在某些情况下可能会存在以下情况: 1. 文件不希望被热更新; 2. 文件希望被热更新,但是由于没有被自动检测到而热更新失效; 针对这种情况,除了可以采用下文所提到的 san-hot-loader 配置指定之外,还可以直接在书写具体工程代码的时候,通过添加一些特殊的注释进行标记,san-hot-loader 会去检测这些特殊的注释去执行相应的操作。 #### 禁止热更新 在文件头部或尾部添加以下注释,即可达到禁止该文件被热更新的效果: ```js /* san-hmr disable */ import san from 'san'; export default san.defineComponent({ template: '