npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

san-hot-loader

v0.1.7

Published

San hmr loader

Downloads

33

Readme

San-Hot-Loader

San-Hot-Loader 为基于 Webpack 构建的 San 项目提供热更新功能。能够让 San 项目在调试开发的时候变得更加方便。

安装

代码1-1

$ npm install --save-dev san-hot-loader

配置

您需要在 Webpack 配置文件当中添加 san-hot-loader 相关配置信息。完整的配置信息可参考示例项目当中的 webpack.config.js 配置,其中与 san-hot-loader 有关的配置如下所示:

代码2-1

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

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

// app.js
import san from 'san';

export default san.defineComponent({
    template: '<p>Hello {{name}}</p>',
    initData: function () {
        return {name: 'San'};
    }
});

也可以采用 class 的方式:

代码3-2

import {Component} from 'san';
export default class App extends Component {
    static template = '<p>Hello {{name}}</p>';
    initData() {
        return {name: 'San'};
    }
}

或者采用 ES5 Function Constructor 的方式来定义组件:

代码3-3

var san = require('san');

function App(options) {
    san.Component(this, options);
}
san.inherits(App, san.Component);
App.prototype.template = '<p>Hello {{name}}</p>';
App.prototype.initData = function () {
    return {name: 'San'};
};
module.exports = App;

基于上述例子不难看出,一个功能完整的组件代码文件应包含以下特征:

  1. 文件引入 san 模块(importrequire);
  2. 使用 san 模块所提供的 API(defineComponent、Component)定义组件;
  3. 将定义好的组件作为默认模块导出(export defaultmodule.exports);

以上就是 san-hot-loader 判断文件是否为普通 San 组件的方法。

结合 San-Store 的组件写法

当项目使用 San-Store 时,根据相关文档的说明,需要使用 san-store 提供的 connect 方法将状态源与组件关联起来,如:

代码3-4

import {defineComponent} from 'san';
import {connect} from 'san-store';
import './register-store-actions';

const App = defineComponent({
    template: '<p>Hello {{name}}</p>',
    initData: function () {
        return {name: 'San'};
    }
});
// connect 到默认 store
const NewApp = connect.san({name: 'name'})(App);
export default NewApp;

或者:

代码3-5

import {defineComponent} from 'san';
import {connect} from 'san-store';
import store from './store';

const App = defineComponent({
    template: '<p>Hello {{name}}</p>',
    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-storeimportrequire);
  2. 使用 san-store 提供的 connect.sanconnect.createConnector(store) 得到的方法连接 store 与当前 San 组件获得新的组件;
  3. 将得到的新组件作为默认模块导出(export defaultmodule.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

// 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. 文件不存在任何模块导出(exportexport defaultmodule.exportsexports.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

// 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 会去检测这些特殊的注释去执行相应的操作。

禁止热更新

在文件头部或尾部添加以下注释,即可达到禁止该文件被热更新的效果:

/* san-hmr disable */

import san from 'san';

export default san.defineComponent({
    template: '<div>hello world</div>'
});

开启热更新

热更新包括组件热更新和 San-Store 热更新。

组件热更新需要满足的条件是:当前文件默认导出的模块组件对象。在满足该前提下,可以使用以下注释指定热更新:

// ./component.js
import sanComponentWrapper from './wrapper'
import componentDescriptor from './descriptor';

export default sanComponentWrapper(componentDescriptor);

/* san-hmr component */

其中:

// ./wrapper.js

import san from 'san';
export default function (descriptor) {
    return san.defineComponent(descriptor);
}

// ./descriptor.js

export default {
    template: '<div>hello world</div>'
}

很明显在上述的示例代码当中 component.js 是无法被 san-hot-loader 自动检测判定为 San 组件文件,因此可以通过注释 /* san-hmr component */ 主动告知对该文件执行热更新。

同样,对于 San-Store 也可以使用 /* san-hmr store */ 来实现对 Store 的热更新:

import store from './custom-store.js';

store.addAction('increase', )
// ./custom-action.js
import store from './custom-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-hmr store */

其中:

// .custom-store.js
import {Store} from 'san-store';
export default new Store({
    initData: {
        num: 0
    }
});

在这种情况下,san-hot-loader 无法通过自动检测手段判定 ./custom-action.js 需要执行热更新,因此可以通过 /* san-hmr store */ 进行标记。

配置

san-hot-loader 提供一系列配置,通过 webpack loader 的 options 配置项传入,如果使用的是 babel 插件时,在配置上也是一样的:

// webpack loader 配置
module.exports = {
    // ...
    module: {
        rules: [
            // ...
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'san-hot-loader',
                        options: {
                            enable: process.env.NODE_ENV === 'development',
                            component: {
                                patterns: [
                                    /\.san\.js$/,
                                    'auto'
                                ]
                            },
                            store: {
                                patterns: [
                                    function (resourcePath) {
                                        return /\.store\.js$/.test(resourcePath);
                                    },
                                    'auto'
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    }
}
// Babel Plugin 配置
module.exports = {
    // ...
    module: {
        rules: [
            // ...
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            plugins: [
                                [
                                    'san-hot-loader',
                                    {
                                        enable: process.env.NODE_ENV === 'development',
                                        component: {
                                            patterns: [
                                                /\.san\.js$/,
                                                'auto'
                                            ]
                                        },
                                        store: {
                                            patterns: [
                                                function (resourcePath) {
                                                    return /\.store\.js$/.test(resourcePath);
                                                },
                                                'auto'
                                            ]
                                        }
                                    }
                                ]
                            ]
                        }
                    }
                ]
            }
        ]
    }
}

接下来将详细介绍 san-hot-loader 配置项的使用方法。

enable

  • enable {boolean} 是否使能该 loader,默认值为 true。一般配合环境变量一起使用,如:
// webpack.config.js
{
    loader: 'san-hot-loader',
    options: {
        enable: process.env.NODE_ENV !== 'production'
    }
}

component.enable

  • component.enable {boolean} 是否开启 San 组件热更新,默认值为 true,即默认开启:
{
    loader: 'san-hot-loader',
    options: {
        component: {
            enable: false // 关闭 San 组件热更新
        }
    }
}

component.patterns

  • component.patterns {Array.<Object>} 开启热更新的 San 组件的路径匹配模式,默认值为:[{component: 'auto'}],即采取自动检测的模式。

其中 component 的取值除了 'auto' 之外,还可以传入正则表达式和函数来对进行文件路径匹配,比如:

{
    loader: 'san-hot-loader',
    options: {
        component: {
            patterns: [
                /\.san\.js$/,
                function (resourcePath) {
                    // resourcePath 为当前资源的绝对路径
                    // return true 则表示匹配成功
                    return /\.san\.js$/.test(resourcePath);
                },
                'auto'
            ]
        }
    }
}

san-hot-loader 会优先匹配到后缀为 .san.js 的文件时,会直接向该文件注入热更新代码,匹配失败后,再按顺序执行剩余的匹配规则。

store.enable

  • store.enable boolean 是否开启 San-Store 热更新,默认为 true,即默认开启:
{
    loader: 'san-hot-loader',
    options: {
        store: {
            enable: false
        }
    }
}

store.patterns

  • store.patterns {Array.<Object>} 开启热更新的 San Store 模块路径匹配模式,默认值为:['auto'],即采取自动检测的模式。

无论是使用 san-store 提供的全局 store 还是自定义 store,同样也可以通过正则表达式和函数的方式去指定文件,在规则上与 component 配置一致:

{
    loader: 'san-hot-loader',
    options: {
        store: {
            patterns: [
                /\.store\.js$/,
                function (resourcePath) {
                    return /\.store\.js$/.test(resourcePath);
                },
                'auto'
            ]
        }
    }
}

示例

项目 examples 提供了一个简单但功能完整的示例,可以将本项目 clone 下来,运行该示例,并尝试修改示例当中的代码来感受热更新为开发所带来的便利。