webpack之import 异步import

模块标准: CommonJS、AMD、CMD、ES6 Module

CommonJS是Node.js原生支持的模块标准. 使用module.exports和require()函数.
AMD和CMD比较相似, AMD的实现有require.js, CMD的实现有Sea.js.
ES6 Module引入importexport两个关键字, 是Webpack推荐的模块标准.

export 与 import

export

首先module.exports = ...export关键字不能混用, 在Wbpack中优先使用export关键字.
export对一个Module对象进行操作, 而不是普通的js对象, 最后module.exports赋值为该对象以导出.
使用ES6语法导出的是一个Module对象, 根据default字段, 有"默认导入"和"具名导出"两种说法.

let value = 88;
let value2 = 66;

function printValue() {
    console.log(value);
}

// 导出"默认"变量作为一个{}对象
export default {
    value2: value, // 导出变量的同时重命名
    printValue,
};
// export default value; // 也可以将"默认"变量导出为一个变量或函数, 但不能多次导出"默认"变量
// export default value2 = value; // 重命名

// 具名导出
export { value as value2, value2 as value }; // 导出多个非默认变量, 同时重命名别名
// export { value: value2, value2: value }; // 语法错误
export var foo = printValue; // 导出单个非默认变量, 同时重命名
console.log({ foo }); // 现在 foo 是合法变量

import

import会判断对应模块入口文件(通常是/index.js)中module.exports是普通js对象还是Module对象, 从而实现兼容:

如果是Module对象, 则有默认导出和其它导出(具名导出)之分
如果是普通js对象, 那么module.exports就是默认导出

import * as A from './test'; // 等价于C, 这种语法通常在使用import关键字引用浏览器和服务器通用模块时使用, 因为这些模块不导出Module对象
import B from './test'; // 默认导入
const C = require('./test'); // Node.js原始require语法, 可理解为伪代码: C = test.module.exports;
console.log({ A });
console.log({ B });
console.log({ C });

// 更新
import { default as D } from './test'; // 等价于B


高阶用法

集线器

可以将一个js文件作为路由集线器, 导入其它js的非默认同时导出:

export { DefaultLoadingManager, LoadingManager } from './loaders/LoadingManager.js';

我们将之前的文件命名为test2.js, 在test1.js中路由:

export { default } from './test2'; // 导出default
export { foo } from './test2'; // 导出非默认变量foo
export * from './test2'; // 导出全部非默认变量. 也就是说导出不会包含含default字段

// 也就是说, 导出test2全部可导成员需要以下两步
export * from './test2';
export { default } from './test2';

// 有时我们需要导入默认导出, 又需要导入普通的CommonJS导出, 可以这样写:
import React, { Component } from 'react';
// 那么之前的导出全部成员可以这么写吗? (疑问)
export *, { default } from './test2';
// 导入这样写可以吗? (疑问) 不可以!!!
import * as React, { Component } from 'react';

构建通用包时, 建议不使用ES6模块

以下四种React的引入是一样的,显然react包没有使用ES6模块:

import ReactA, { createElement as e, default as ReactB } from 'react';
import * as ReactC from 'react';
const ReactD = require('react');
console.log(ReactA === ReactB); // true
console.log(ReactA === ReactC);
console.log(ReactA === ReactD);

import一个目录

当我们导入一个目录时, 会尝试执行该目录下的index.js文件. 并且目录优先于同名的js文件, 除非导入时显式指定.js后缀.
在Windows下文件名不区分大小写, 所以Index.js也可以编译, 但是在Linux下就完蛋了...!这也算是一个坑吧

异步import

function(string loader_and_file): Promise

动态加载模块。调用 import() 之处被视为分割点,意思着被请求的模块和它引用的所有子模块,会分割到一个单独的 chunk 中。
异步import, 模块的处理过程将作为一个分割点单独打包为独立模块, 再通过ajax请求, 请求路径是相对于引用脚本的URL, 所以对于单页应用来说没有问题.

// "."表示当前js文件, 使用raw-loader异步加载当前js文件的文本内容
import('!raw-loader!.').then(({ default: text }) => {
    this.setState({ code: text });
});

非入口点文件

通过异步import打包后的文件称为非入口点文件, 文件名可以通过Webpack配置中的config.output.chunkFilename确定:

    output: {
        filename: '[name].js',
        path: DIR_DIST,
        chunkFilename: 'async/[id].js', // 此选项确定非入口块文件的名称
    },

Magic Comments可以通过js注释的方式控制每一个异步import.

官方文档

https://webpack.docschina.org/api/module-methods/
异步import及其魔法注释
https://webpack.js.org/api/module-methods/#magic-comments

END

原文地址:https://www.cnblogs.com/develon/p/13560949.html