webpack静态模型快打包工具
webpack是一个现代JavaScript应用程序的静态模块打包工具。
当webpack处理应用程序时,它会在内部构建一个依赖图(dependency [/dɪˈpendənsi/] graph [/ɡræf/]),此依赖图会映射项目所需的每个模块,并生成一个或多个bundle包!webpack本身是基于node.js开发的!
webpack是大前端时代下,实现项目的工程化和自动化的工具。
还有几个打包工具:grunt、gulp、fis、webpack、snowpack、vite…
为啥使用webpack
- 代码转换:TypeScript编译成JavaScript、LESS/SCSS编译成CSS、ES6/7编译为ES5、虚拟DOM编译为真实的DOM等等…
- 文件优化:压缩JS、CSS、HTML代码,压缩合并图片,图片BASE64等
- 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码等
- 模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件
- 自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器
- 代码校验:Eslint代码规范校验和检测、单元测试等
- 自动发布:自动构建出线上发布代码并传输给发布系统
- …
1.CommonJs规范 & ES6Module规范
模块化变成进化历史
- 单例设计模式
- AMD [require.js]
- CommonJs
- CMD [sea.js]
- ES6Module
1) 单例设计模式
特点:单例设计模式作为早期的的模块化编程方案,是可以实现模块区分的,避免全局变量污染的;但是随着前端的发展,我们要拆分的模块越来越多,而且模块和模块之间的依赖也越来越复杂,单例模式在处理模块依赖的时候,容易把人搞”疯”!
- 在html中引入JS文件需要根据依赖顺序,以此导入
let xxxModule = (function () {
let time = new Date();
const query = function query() {
// ...
};
const handle = function handle() {
// ...
};
// 把供其它板块调用的方法,暴露到全局对象上
//「局限:暴露的内容比较多,则还会引发全局变量冲突」
// window.query = query;
return {
query,
handle
};
})();
复制代码
2)AMD模块「require.js
require.js是AMD模块化思想:按需导入,依赖管理
- AMD思想的一个问题:所有依赖的模块都需要前置导入
- 好处: 各模块进行管理
- [‘模块路径’]
- 依赖模块
require(['依赖模块A','B',...],function(A,B,...){ })
- 定义模块
define(function(){ })
- 定义加依赖模块
define(['依赖模块A','B',...],function(A,B,...){ })
//main.js
require.config({
//全局配置
baseUrl: 'js/lib',
});
require(['moduleB', 'moduleA'], function (moduleB, moduleA) {
console.log(moduleB.average(10, 20, 30, 40, 50));
});
//moduleA.js
define(function () {
return {
sum(...args) {
let len = args.length,
firstItem = args[0];
if (len === 0) return 0;
if (len === 1) return firstItem;
return args.reduce((total, item) => {
return total + item;
});
}
};
});
//moduleB.js
define(['moduleA'], function (moudleA) {
return {
// 求平均数(去掉最大最小值)
average(...args) {
let len = args.length,
firstItem = args[0];
if (len === 0) return 0;
if (len === 1) return firstItem;
args.sort((a, b) => a - b);
args.pop();
args.shift();
return (moudleA.sum(...args) / args.length).toFixed(2);
}
};
});
复制代码
3)CommonJS模块 [现在我们还可以使用]
优点:随导随用
CommonJS模块规范
- 导出 module.exports
- 导入 require(‘./模块地址’)
module.exports = {};
- let obj = require(‘./模块地址’);
- let {sum} = require(‘./模块地址’);【直接解构赋值】
module.exports = xxx;
- let xxx = require(‘./模块地址’);
导入自己写的模块需要加“./”这样的地址,如果是导入Node内置模块(或者安装的第三方模块),直接写模块名字即可!!
特点:只能在Node环境下运行,不能在浏览器端运行
淘宝“玉伯”之前开发过一款插件sea.js,旨在让浏览器端也能运行CommonJS模板规范,他把这种模块思想称之为“CMD”
现在sea.js已经不用了,但是我们使用webpack打包的时候,webpack是支持commonJS规范的,所以我们可以直接使用commonJS规范写代码,最后webpack帮我们编译为浏览器可以识别的代码!
/* ---A.js--- */
const sum = function sum(...params) {
return params.reduce((result, item) => {
return result + item;
});
};
// 暴露一些API
module.exports = {
sum
};
/* ---B.js--- */
let name = '哈哈';
let A = require('./A');
const average = function average(...params) {
return (A.sum(...params) / params.length).toFixed(2);
};
module.exports = {
average
};
/* ---main.js--- */
let A = require('./A');
console.log(A.sum(10, 20, 30, 40));
let B = require('./B');
console.log(B.average(10, 20, 30, 40));
复制代码
4)ES6Module模块
ES6Module中的模块导入导出规范【export
或者export
default
导出,impor
t导入】
导入import,必须写在模块的最开始
type="module"
直接在浏览器端开启ES6Module规范;并且需要保证页面是基于http或者https协议【Open with Live Server】 <script type="module" src="https://juejin.cn/post/main.js"></script>
1.导出:export
export const n = 100;
export const m = 200;
1.导入:import
import * as A from ‘./A.js’
使用的时候:A.n 、 A.m
2.导出【export default只能用一次】
export default 对象/函数
export default { sum,func }
2.导入
import A from ‘./A.js’
3.导出 export default function sum(){ }
3.导入 import sum from ./A.js’
同一个模块中,“export default”只能用一次
- export {xxx : xxx};
webpack环境下既支持CommonJS规范,也支持ES6Module规范,而且可以支持两者混着用【用CommonJS规范导入,用ES6Module规范导出…】
A.JS
// 单例模式实现模块化
const sum = function sum(...params) {
let len = params.length;
if (len === 0) return 0;
if (len === 1) return params[0];
return params.reduce((result, item) => {
return result + item;
});
};
//export default sum;
export default{
sum
};
B.JS
import A from './A.js';
// 浏览器端使用ES6Module,'.js'不能忽略 [webpack中使用可以忽略后缀名]
const average = function average(...params) {
let total = A.sum(...params);
return (total / params.length).toFixed(2);
};
export default average;
main.js
// import 只能放在最开始的位置
import A from './A.js';
import average from './B.js';
console.log(A.sum(12,23,34,45));
console.log(average(12,23,34,45));
index.html
<!--
type="module" 直接在浏览器端开启ES6Module规范
并且需要保证页面是基于HTTP/HTTPS协议预览 [Live Server]
-->
<script type="module" src="https://juejin.cn/post/main.js"></script>
复制代码
- 支持export导出多个”导入方式”
c.js
export let n = 100;
export let m = 200;
export const fn = function fn() { };
main.js
// 支持export导出多个"导入方式"
import * as C from './C.js';
console.log(C);
/* import { n, m, fn } from './c.js';
console.log(n, m, fn); */
复制代码
- 支持export default函数
D.js
export default function () {
console.log('fn');
};
main.js
//支持 export default 函数
import fn from './D.js';
console.log(fn);
复制代码
- 支持 export default 对象
E.js
const fn = function fn() { };
const sum = function sum() { };
export default {
fn,
sum
};
main.js
//支持 export default 对象
import E from './E.js';
//浏览器端,此种方案:不能直接import的时候给E解构赋值,但是获取到E后,可以单独自己解构
// const {sum,fn}=E
console.log(E);
复制代码
/* ---index.html--- */
<!--
type="module" 让浏览器支持ES6Module规范
必须是基于HTTP/HTTPS协议预览
-->
<script type="module" src="https://juejin.cn/post/main.js"></script>
/* ---main.js--- */
/* 导入,必须写在模块的最开始 */
import A from './A.js';
import average from './B.js';
console.log(A.sum(10, 20, 30, 40));
console.log(average(10, 20, 30, 40));
/* ---A.js--- */
const sum = function sum(...params) {
return params.reduce((result, item) => {
return result + item;
});
};
// 分别导出多个
// export const AA = 'xx';
// export const BB = 'xx';
// 导出一个
// export default sum;
export default {
sum
};
/* ---B.js--- */
import A from './A.js';
const average = function average(...params) {
return (A.sum(...params) / params.length).toFixed(2);
};
export default average;
复制代码
2.NPM的操作阶段
- 安装在 全局 & 本地 的区别
- 安装在本地如何使用命令
- npx 「npm > 5.2」
3.webpack的操作基础
1)安装
想用webpack必须提前安装:webpack webpack-cli
- 1.安装在全局npm i webpack webpack-cli -g
- 卸载:npm uninstall webpack webpack-cli -g
- 能直接使用命令webpack
- 所有项目都用相同版本的webpack;但是如果想用不同版本的webpack是不容易实现【容易引起版本冲突】
- 2.安装在当前项目中npm i webpack webpack-cli –save-dev
- 或者yarn add webpack webpack-cli -D
- 使用yarn之前需要先执行yarn init -y生成package.json文件
- 不能直接使用webpack命令
- 每个项目有自己单独版本,不会导致版本冲突
- 或者yarn add webpack webpack-cli -D
———————- 如何实现:安装在本地项目中,但是也可以使用命令进行打包?
- 1.当npm版本 > 5.2,直接使用npx运行对应的命令即可 $ npx webpack
- 2.在package.json中配置可执行的脚本命令
"scripts": {
// 脚本名字:要执行的命令 [前提:在node_modules目录的.bin文件夹下,需要有webpack这个命令文件]
"build":"webpack"
}
复制代码
- npm run build 【npm run 配置的脚本名字】
2)零配置使用
npm run build
默认查找根目录下的src文件夹下的index.js文件;默认打包完成的目录为:dist目录下的main.js
* 默认会打包SRC目录中的JS文件(入口默认index.js)
* 打包完成的目录默认是DIST/MAIN.JS
* webpack默认支持CommonJS和ES6 Module的模块规范,依此进行依赖打包
*/
$ npx webpack
复制代码
3)自定义基础配置
webpack.config.js || webpackfile.js
const path = require('path');
module.exports = {
// 设置打包模式 development:开发模式 production:生产模式[默认]
// 开发模式下的特点是:默认不压缩
// 生产模式下的特点是:默认压缩
mode: 'development',
// 打包入口文件目录
entry: './src/main.js',
// 打包后的输出目录
output: {
// 输出文件名
filename: 'bundle.js',
// 输出的路径 [必须是一个绝对路径]
path: path.resolve(__dirname,'dist')
}
};
复制代码
- development 开发模式 [默认不压缩]
- production 生产模式 [默认压缩]
4)自定义配置文件名
执行webpack命令
- 自己不写 webpack.config.js,则默认找 src/index.js 打包输出到 dist/main.js
- 如果自己写了 webpack.config.js,则按照自己写的规则出来
- 真实项目中,往往是我们需要自己去区分环境 [开发环境 & 生产环境],两个环境走不同的配置
指定webpack打包时候,查找的规则文件
- @1 创建不同的规则文件
- webpack.config.development.js 【开发环境的打包规则】
- webpack.config.production.js 【生产环境的打包规则】
- @2 配置不同的脚本命令,执行某个命令,让其走自己对应的规则
scripts": {
"serve": "webpack --config webpack.config.development.js",
"build": "webpack --config webpack.config.production.js"
}
复制代码
- $ npx webpack –config webpack.config.development.js
- 可在package.json中配置可执行的脚本命令(区分开发环境)
webpack.config.js
const path = require('path');
module.exports = {
// 设置打包模式 development:开发模式 production:生产模式[默认]
// 开发模式下的特点是:默认不压缩
// 生产模式下的特点是:默认压缩
mode: 'production',
// 打包入口文件目录
entry: './src/main.js',
// 打包后的输出目录
output: {
// 输出文件名
filename: 'bundle.js',
// 输出的路径 [必须是一个绝对路径]
path: path.resolve(__dirname,'dist')
}
};
复制代码
webpack.config.development.js 开发环境
/* 开发环境的打包规则 */
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'dist')
}
};
复制代码
webpack.config.production.js 生产环境
/* 生产环境的打包规则 */
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/main.js',
output: {
// [hash]:每一次打包的时候,根据文件内容不同,生成不同的HASH值,保证文件代码更新,生成的文件名字是不同的
filename: 'bundle.[hash].min.js',
path: path.resolve(__dirname,'dist')
}
};
复制代码
5)使用插件打包 HtmlWebpackPlugin
- 在src文件夹下新建一个index.html,然后去webpack.config.js中写配置
- $ npm i html-webpack-plugin -–save-dev
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...,
//=>在webpack中使用插件
plugins: [
new HtmlWebpackPlugin({
//=>指定自己的模板
template: './src/index.html',
//=>输出的文件名
filename: 'index.html',
//=>给引入的文件设置HASH戳(清除缓存的),也可以在output中设置 filename: 'bundle.[hash].js' 来生成不同的文件
hash: true,
//=>控制是否以及以何种方式最小化输出
//=>https://github.com/kangax/html-minifier
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true,
removeEmptyAttributes: true
}
})
]
}
复制代码
6)清除打包工具 CleanWebpackPlugin
- 每一次打包工具之前,要清除之前打包的内容
- $ npm i clean-webpack-plugin –save-dev
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports={
plugins:[
new CleanWebpackPlugin()
]
};
复制代码
7)配置webpack-dev-server
- $
npm install webpack-dev-server –save-dev
- 配置DEV-SERVER:创建一个本地服务,实时预览编译后的内容 [开发环境下需要]
npm run serve
:自动打开浏览器,实时监听代码更新状态,当代码变化的时候,页面会自动刷新
- $ npm run serve -> webpack server 【开发环境】
- 按照规则打包编译【把编译后的文件放在内存中{临时的地方},没有放在dist目录下】
- webpack-dev-server插件,帮助我们启动一个web服务【按照devServer配置的规则来处理】,而服务访问的内容就是去内存中查找
- 代码修改后,启动的服务会自动监听代码改变,重新进行编译,并且通知浏览器自动更新
- $ npm run build -> ‘webpack’ 【生产环境】
- 按照规则打包编译,把编译后的文件输出到dist目录中
- 真实开发中,我们会把dist打包后的内容部署到服务器上
/* webpack.config.js */
//=>配置DEV-SERVER
devServer: {
//=>端口
port: 3000,
host: '127.0.0.1',
//=>开启GZIP压缩
compress:true,
//=>显示编译进度
progress: true,
//=>指定访问资源目录
contentBase: path.resolve(__dirname, "dist"),
//=>自动打开浏览器
open: true,
//=>开启热更新
hot:true,
//=>请求代理
proxy:{
"/":{
target:"http://localhost:8888",
secure: false, //若为true则表示是https,false是http
changeOrigin: true //把请求头当中的host值改成服务器地址
}
}
}
/* package.json */
"scripts": {
"serve": "webpack server",
"build": "webpack"
}
复制代码
4. webpack中的加载器loader:处理样式的
$ npm i css-loader style-loader less less-loader autoprefixer postcss-loader –save-dev
- less sass stylus 前端样式预编译语言
- less less-loader 编译less代码处理成css代码的
- sass sass-loader
- css-loader 解析CSS「@import url…」导入外部资源的代码
- style-loader 把CSS样式插入到 head中【内嵌式】
- less less-loader 编译less代码的
- autoprefixer postcss-loader 自动加前缀【-webkit-、-moz-、-ms-、-o-】根据浏览器兼容问题
- -webkit-transition:.5s;
- -ms-transition:.5s;
- -moz-transition:.5s;
- -o-transition:.5s;
- transition:.5s;
module.exports = {
//=>配置模块加载器LOADER
module: {
//=>模块规则:使用加载器(默认从右向左执行,从下向上)
rules: [{
test: /\.(css|less)$/, //=>基于正则匹配哪些模块需要处理
use: [
"style-loader", //=>把CSS插入到HEAD中
"css-loader", //=>编译解析@import/URL()这种语法
"postcss-loader", //=>设置前缀
{
loader: "less-loader",
options: {
//=>加载器额外的配置
}
}
]
}]
}
}
复制代码
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
复制代码
package.json
// https://github.com/browserslist/browserslist
"browserslist": [
"> 1%",
"last 2 versions"
]
复制代码
1) mini-css-extract-plugin 抽离CSS内容
- $ npm i mini-css-extract-plugin –save-dev mini-css-extract-plugin 抽离CSS内容
const MiniCssExtractPlugin=require('mini-css-extract-plugin');
module.exports = {
plugins: [
//=>使用插件
new MiniCssExtractPlugin({
//=>设置编译后的文件名字
filename: 'main.[hash].css'
})
],
module: {
rules: [{
test: /\.(css|less)$/,
use: [
// "style-loader",
//=>使用插件中的LOADER代替STYLE方式
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader"
]
}]
}
}
复制代码
5. 设置优化项压缩CSS/JS
$ npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin terser-webpack-plugin –save-dev
const UglifyjsWebpackPlugin=require('uglifyjs-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin= require('optimize-css-assets-webpack-plugin');
module.exports = {
//=>设置优化项
optimization: {
//=>设置压缩方式
minimizer: [
//=>压缩CSS(但是必须指定JS的压缩方式)
new OptimizeCssAssetsWebpackPlugin(),
//=>压缩JS
//new UglifyjsWebpackPlugin({
//cache: true, //=>是否使用缓存
//parallel: true, //=>是否是并发编译
//sourceMap: true, //=>启动源码映射(方便调试)
//}),
new TerserPlugin()
]
}
};
复制代码
6. webpack中图片的处理
$ npm i file-loader url-loader html-withimg-loader –save-dev
module.exports = {
module: {
//=>模块规则:使用加载器(默认从右向左执行)
rules: [{
test: /\.(png|jpe?g|gif)$/i,
use: [{
//=>把指定大小内的图片BASE64
//=>不在指定范围的采用file-loader进行处理
loader: 'url-loader',
options: {
limit: 200 * 1024,
outputPath:'/images', // 在dist中输出images
//name:'[name].[ext]' // 不把图片进行混淆,该是什么名字就是什么名字,该是什么后缀还是什么后缀,不加这个配置,可以防止盗图也防止图片冲突,也可以防止缓存。「默认为混淆处理」
}
}],
include: path.resolve(__dirname, 'src'), // 编译的时候,我只对那个文件夹下的进行编译
exclude: /node_modules/ //排除那个目录一定不编译
}, {
//字体图标,没有办法进行base64,但是可以使用file-loader处理
test:/\.(svg|eot|ttf|woff|woff2)$/i,
use:"file-loader"
}, {
//html中的image也进行处理
test: /\.html$/,
use: ['html-withimg-loader']
}]
}
}
复制代码
7. 基于babel实现ES6的转换
npm i babel-loader @babel/core @babel/preset-env 核心这是哪个
@babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime –save-dev
npm i @babel/runtime @babel/polyfill需要下载生产环境
- babel-loader @babel/core @babel/preset-env 核心这三个
- rules 中继续添加{test: /.js$/, use: [{ loader: ‘babel-loader’,//使用加载器 babel-loader 然后用options配置项 options: { presets:[“@babel/preset-env”] } }] }
- options: { presets:[“@babel/preset-env”] } 通过这个语法包把es6转译成es5
- 但是只能转换一些语法类操作,对于很多es6内置的API无法转换
- npm i @babel/runtime @babel/polyfill 需要下载在生产环境
- 在main.js中通过 import ‘@babel/polyfill’ 导入
- 把es6无法转化的Promise,它主要是自己写了一个原生Promise。后面我们再使用就是用的人家写好的
- 如果在项目中要兼容IE10、11 除了需要用到@babel/preset-env这个语法包,还需要把内置的API进行转化
- 如果需要实现内置API的兼容,我们需要在程序中导入@babel/polyfill 「这个包把ES6内置的API自己实现了一遍」
module.exports = {
module: {
rules: [{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
//=>转换的语法预设(ES6->ES5)
presets: [
"@babel/preset-env"
],
//=>基于插件处理ES6/ES7中CLASS的特殊语法
plugins: [
["@babel/plugin-proposal-decorators", {
"legacy": true
}],
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
"@babel/plugin-transform-runtime"
]
}
}],
//=>设置编译时忽略的文件和指定编译目录
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}]
}
}
复制代码
8. 多入口 & 多出口
const htmlPlugins = ['index', 'login'].map(chunk => {
return new HtmlWebpackPlugin({
template: `./${chunk}.html`,
filename: `${chunk}.html`,
hash: true,
chunks:[chunk,'jquery'],
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true,
removeEmptyAttributes: true
}
});
});
module.exports={
entry: {
index: "./src/index.js",
login: "./src/login.js",
jquery:"./src/jquery.js"
},
output: {
filename: "[name].[hash].js",
path: path.resolve(__dirname, "dist")
},
plugins:[
...htmlPlugins
]
};
复制代码
脚手架vue/cli
- 1.脚手架: vue->@vue/cli react->create-react-app
- 2.基于脚手架创建项目,会默认帮我们把所有的webpack配置项设置好
- 3.vue vue-cli老版本 @vue/cli 新版本
- 4.npm i @vue/cli -g 全局安装vue/cli
- 5.vue create xxx 名字「不能出现中文和特殊符号以及大写字母」
- 1.@vue/cli是vue框架的“脚手架”【基于脚手架创建的项目,会帮我们把webpack配置好】
- 2.默认处理:
- 安装了vue模块
- 完成了webpack的常规配置【模式、入口、出口、加载器、插件、优化项…】
- 支持ESLint语法检测:编写的代码不符合语法规范,编译的时候会报错
- 3.默认把webpack配置文件放在了node_modules中了
- npm run serve执行vue-cli-service serve这个命令
- 编译打包代码【放在内存中】
- 基于webpack-dev-server启动一个web服务,运行编译的内容
- 支持热更新,代码修改后,及时编译,实时刷新浏览器预览
- npm run build执行vue-cli-service build这个命令
- 编译打包代码
- 放在dist目录下
- npm run serve执行vue-cli-service serve这个命令
- 4.如何自己修改默认配置项?
- 根目录创建 vue.config.js
- publicPath 前缀 是根目录还是当前目录 / 是根目录
- outputDir 打包放在那个文件下
- lintOnSave: false eslint是否开启
- productionSourceMap
- 加map 为了报错可以知道是哪里报错,但是打包编译速度会变慢 不方便调试
- 根目录创建 vue.config.js
- 5.处理浏览器兼容
- package.json 根据兼容浏览器:设置css前缀 & 实现JS语法转换
- polyfills
// package.json
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
复制代码
vue中的package.json
文件目录
- node_modules 安装的模块
- public 页面的模板,多个页面开发就写多个模版
- favicon.ico 头部图标
- index.html 首页的模版
- <%= BASE_URL %> 指的是public这个目录,最后要经过webpack编译
- <%= htmlWebpackPlugin.options.title %> 页面的title可以webpack配置项中指定
- ……
- 为什么el的指定模板不能使用html/body?
- 因为可以new Vue很多次但是html/body只有一个。
- index.html模板页面中,我们可能会自己导入一些资源或者写一些代码,这些东西不想最后和其他组件中的样式和代码打包合并在一起。「打包在一起太大了,我们想提前加载和渲染我们写的这些代码,或者直接写成内嵌式,减少页面白屏」
- 例如:
- 把动态计算rem和px换算比例的代码单独写在这里,优先加载
- 因为打包后的文件较大,加载需要一些时间,而等待加载的过程会出现白屏效果,此时我们可以写一些Loading或者骨架屏的代码。「客户端loading」 给用户人性化的体验,「减少白屏时间」
- ……
- 因为webpack中是基于ES6Module或者CommonJs规范实现导入导出和打包的,如果我们的JS不支持这两个规范,这样就无法在webpack中使用,只能基于
第一次写,如果有什么不足或者有错的地方,希望大家多多提点!谢谢(* ̄︶ ̄)