webpack的小技巧

78 阅读1分钟

问题:有时候要定义一个变量,这个变量是动态生成的,例如,根据urlUAhttp response header上的某些参数生成,这个变量会跨模块的多次使用,有人想直接定义在浏览器的window全局对象上,直接window.xxx用。

这种做法很危险,而且需要手动维护模块的依赖关系。下面用一个典型的例子说明,需求是有一个isWap变量,表示当前是什么平台,在各个模块都可能会使用。

  • window对象上定义变量:

入口文件,index.js

import Home from "./containers/Home";

const coin = () => Math.random() < 0.5;
window.isWap = coin();

new Home().render();

index.js做的事情是:引入Home视图类,在window对象上定义isWap变量并赋值,然后实例化Home视图类,调用视图类实例的render方法。

Home视图类,containers/Home/index.js:

import * as actionCreators from "./actions";

console.log("Home component isWap: ", window.isWap);

class Home {
  render() {
    console.log("Home component render isWap: ", window.isWap);
    actionCreators.toggle();
    return "home";
  }
}

export default Home;

这是Home视图类,重点注意两个console.log的位置,打印window.isWap变量。

Home视图类依赖的actionscontainers/Home/actions.js

console.log("actions outside isWap: ", window.isWap);

function toggle() {
  console.log("actions inside isWap: ", window.isWap);
  return {
    type: "TOGGLE",
    payload: {}
  };
}

export { toggle };

这是Home视图类依赖的action模块,重点注意两个console.log的位置,第一个在模块作用域,第二个在toggle函数中,两个console.log的执行时机是不一样的,第一个会在模块被加载(importrequire)时就执行,第二个只有在toggle函数调用时才会执行。

运行结果:

actions outside isWap:  undefined
Home component isWap:  undefined
Home component render isWap:  false
actions inside isWap:  false

actions.jsHome.js的模块作用域中的打印的window.isWapundefined,这是不符合期望的。原因很简单,import Home视图类模块时,还没有执行到给window对象上定义isWap变量的语句,Home视图类模块作用域中的console.log会先执行。

这就出现模块(代码)依赖顺序的问题了,其他模块要使用window.isWap,必须要保证在其他模块被导入之前,window.isWap已经存在并有值。当模块越来越多,依赖关系越来越复杂,手动维护是不现实的。

注意: 本例中,就算把入口文件改写成如下:

const coin = () => Math.random() < 0.5;
window.isWap = coin();

import Home from "./containers/Home";

new Home().render();

结果是一样的,因为import有作用域提升。

包括Webpackrequire.js等模块定义,构建打包工具,作用之一,就是用来处理模块依赖顺序(依赖关系),不用再手动的维护传统的script标签的顺序。

  • 定义在模块中,通过export导出使用

index.js

import Home from "./containers/Home";
new Home().render();

containers/Home/index.js

import * as actionCreators from "./actions";
import { isWap } from "../../platform.service";

console.log("Home Component outside isWap: ", isWap);

class Home {
  render() {
    console.log("Home component render isWap: ", isWap);
    actionCreators.toggle();
    return "home";
  }
}

export default Home;

containers/Home/actions.js

import { isWap } from "../../platform.service";

console.log("Home action outside isWap: ", isWap);

function toggle() {
  console.log("Home action inside isWap: ", isWap);
  return {
    type: "TOGGLE",
    payload: {}
  };
}

export { toggle };

platform.service.js模块中定义isWap,并导出

const coin = () => Math.random() < 0.5;
const isWap = coin();

export { isWap };

运行结果:

Home action outside isWap:  false
Home Component outside isWap:  false
Home component render isWap:  false
Home action inside isWap:  false

运行结果是符合期望的,需要isWap变量的地方都显示的导入了platform.service.js模块。Webpack会自动处理模块的依赖顺序(依赖关系),保证isWap在被其他模块使用之前,有值。
这种做法很清晰,可读性,可维护性,可扩展性都很好,符合模块化高内聚,低耦合的特点。