基础的写法

还是mdn清晰:

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
// Import individual features
import { export } from "module-name";
import { export1 , export2 } from "module-name";

// Import default export
import defaultExport from "module-name";

// Import all of a module's exports as a module object
import * as name from "module-name";

// Import renamed exports 
import { export as alias } from "module-name";

// Import a module for side effects only
import "module-name";

// Combinations
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";

// Dynamic module import
var promise = import("module-name"); // This is a stage 3 proposal.
// Exporting individual features
export let name1, name2, , nameN; // also var, const
export let name1 = , name2 = , , nameN; // also var, const
export function functionName(){...}
export class ClassName {...}

// Export list
export { name1, name2, , nameN };

// Renaming exports
export { variable1 as name1, variable2 as name2, , nameN };

// Default exports
export default expression;
export default function () {  } // also class, function*
export default function name1() {  } // also class, function*
export { name1 as default,  };

// Aggregating modules 汇总页面
export * from ;
export { name1, name2, , nameN } from ;
export { import1 as name1, import2 as name2, , nameN } from ;
export { default } from ;
export {default as none} from "./none.js"; 

// In parentModule.js
export { myFunction, myVariable } from 'childModule1.js';
export { myClass } from 'childModule2.js';
// In top-level module
import { myFunction, myVariable, myClass } from 'parentModule.js'

//只有一个输出简化的写法
export default foo;
import foo from 'es6-foo'
import * as fs from 'fs';

If you export default function xyz, you must import xyz or import { default as xyz }
//如果export这么写, 那么import对应的也要解构.
export {out1, out2, out3};
import {foo} from 'es6-foo'
//同样的他们都可以加as语法, 指定名字.
export {out as images};
import {foo as bar} from 'es6-foo'
//多个export
export function function1() {}
export function function2() {}
export default function1;

import defaultExport, { function1, function2 } from './module1'

If you export function xyz, you must import { xyz }
//在node里面就想引入一个文件
import router from './index.js'
//在web里面引入文件也是一样的.
import {postweb} from './node_modules/mtools/index.js';

动态引入

const m = await import('node-fetch');
const fetch=m.default;
浏览器的问题和解决
//引入端这么写:
<script type="module">
  import {images} from '/show/images.js'

//输出端这么写:
//export default out;
export {
    out as images
};
</script>
不要相信其他写法, 比如下面这种就怎么搞都不可以:
<script type="module" src="/show/images.js"></script>
type=module之后, 会导致html里面直接注册事件失败.
 <input type="file" id="input" onchange="handleFiles(this.files)">
  <script type="module">
    function handleFiles() {
      alert('success') //这里不会被执行.
    }
  </script>

我猜测原因是: 因为type=module之后就是异步加载的了, 所以input里面写的onchange就失效了, 因为函数定义并没有被提升上去.

据说是scope问题, 我再试试.

  window.handlefiles=handlefiles; //这样就解决了.

正解再这里: https://stackoverflow.com/questions/44590393/es6-modules-undefined-onclick-function-after-import

然后这个讲的很清楚: https://www.contentful.com/blog/2017/04/04/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling/

在node端用es6 module
// package.json 里面这两个是核心内容.
{
  "type": "module",
  "scripts": {
    "start": "node  --experimental-modules ./index.js",
    //这个start要这么写才行.
  }
}
#发布模块, shell里面这么玩
npm publish
//package.json要指定main, 事实上下面三个字段都是必填项目
{
  "name": "uds",
  "version": "0.0.1",
  "description": "调度算法的node版本",
  "main": "index.js",
  "type": "module",
  "scripts": {

    "start": "node  --experimental-modules ./index.js",
    //这个start要这么写才行.
  }
}

但是这样的情况下eslint会不通过:

#会报下面这个错.
error  Parsing error: 'import' and 'export' may appear only with 'sourceType: module'
//.eslintrc.js
parserOptions: {
  sourceType: 'module',
}

如果start脚本不正确, 会报错:

import mrouter from 'mrouter';
       ^^^^^^^
SyntaxError: Unexpected identifier
"start": "node  ./index.js", //这样就会报错.

"start": "node  --experimental-modules ./index.js",
如果一个模块web有node没有, 或者node有web没有, 那么如何兼容?
//要做动态引入, 比如fetch()就是web有, node没有.
if(typeof fetch ==='undefined'){
  //import fetch from "node-fetch"; 这么写编译不通过, 这是静态引入.
  const m = await import('node-fetch');
  var fetch=m.default; //这里是m.default, 而不是m.fetch, 而且要用var, 因为要突破{}作用域.
}

单单这样还不够, 因为chrome有一个编译过程, 当他碰到import就强制检查是否(.\)满足, 所以需要隔离开. 这里错了, 改进方案再下一段.

index.js, package.json的入口js这么写

import postnode from './postnode.js'
import  postweb from './postweb.js'
const mtools= function mtools(){};
export {postweb,postnode};//这里分别导出给web用的和给node用的
export default mtools;

postnode这么写, 这里不必写成这样, 改进再下一段

import post from "./postweb.js";
const postnode = async function postnode(url, content) {
  const m = await import('node-fetch');
  const fetch=m.default;
  const showdata = await post(url, content, fetch);
  return showdata; // 那么这个就是要处理展示结果集
};
export default postnode;

postweb这么写-> 改名叫postcore

const posturl = async function posturl(url, content, f) {
  const response = await f(url, {
    method: 'POST', // or 'PUT'
    body: content, // data can be `string` or {object}!
    headers: {    	'Content-Type': 'application/json'    },
  }); // ajax拿结果
  const showdata = await response.json();
  return showdata; // 那么这个就是要处理展示结果集
};
export default posturl;
重大更新, 上面的结论错了. 因为我判断错了, 应该判断window, 模块化之后, 全局函数都不能直接用了.

postweb没有问题, 可以改名为postcore.

然后不论是web还是node都可以统一调用下面这个

import post from "./postcore.js";
const postnode = async function postnode(url, content) {
  let fetch;
  if (typeof window === "undefined") { //这里要判断window, 而不是fetch, fetch永远是不存在的.
    const m = await import("node-fetch"); //node是这两行.
    fetch = m.default;
  }else{
		// eslint-disable-next-line no-undef
		fetch=window.fetch;//web是这一行
	}
  const showdata = await post(url, content, fetch);
  return showdata; // 那么这个就是要处理展示结果集
};
export default postnode;

我错怪chrome了, chrome没有bug. 依旧是解释执行的, 之前会报引入错误, 确实是执行到了那个语句.

扩展的阅读
  • chrome使用es6 module做的各种扩展:https://medium.com/front-end-weekly/es6-modules-in-chrome-extensions-an-introduction-313b3fce955b
  • 如何再web使用和node一致的引入方式: http://dplatz.de/blog/2019/es6-bare-imports.html
    • 作者给了5个方案, 包括: unpkg, webpack, owc, polymer, pika.
  • 这里有一些参考文件: https://medium.com/@dmnsgn/es-modules-in-the-browser-almost-now-3638ffafdc68

最终结论: 不要手撸module, 痛不欲生, 用webpack可以一劳永逸的解决问题, webpack真香