13、gulp、angular1项目下index.html文件、三大框架之登录|权限|路由嵌套|状态管理|请求响应拦截、环境、服务器、Linux常见命令、Linux一级目录、Linux|ubuntu|VMware、乌班图里安装搜狗输入法|谷歌浏览器|微信|时间同步|gulp、electron、服务端渲染、_dir、npm、webpack

一、gulp
1、gulp的API
(1)gulp.src(globs[, options])导入文件的路径
(A)globs参数匹配文件路径(路径包括文件名,分为具体路径和通配符路径)。当有多个路径时,该参数为一个数组。
(B)options为可选参数。通常情况下我们不需要用到。
(C)* 匹配文件路径中的0个或多个字符,但不会匹配路径分隔符,除非路径分隔符出现在末尾
(D)** 匹配路径中的0个或多个目录及其子目录,需要单独出现,即它左右不能有其他东西了。如果出现在末尾,也能匹配文件。
(D)gulp.src(['js/*.js','css/*.css','*.html'])
(E)使用数组的方式还有一个好处就是可以很方便的使用排除模式,在数组中的单个匹配模式前加上!即是排除模式,它会在匹配的结果中排除这个匹配,要注意一点的是不能在数组中的第一个元素中使用排除模式
(F)gulp.src([*.js,'!b*.js']) //匹配所有js文件,但排除掉以b开头的js文件
(G)gulp.src(['!b*.js',*.js]) //不会排除任何文件,因为排除模式不能出现在数组的第一个元素中
(2)gulp.dest(path[,options])导出文件的目录
(A)path为写入文件的路径
(B)options为一个可选的参数对象,通常我们不需要用到
(C)gulp.dest()传入的路径参数,只能用来指定要生成的文件的目录,生成的文件名是由导入到它的文件流决定的。
(D)gulp.dest(path)生成的文件路径是我们传入的path参数后面再加上gulp.src()中有通配符开始出现的那部分路径。例如:
(D)gulp.src('script/**/*.js') .pipe(gulp.dest('dist')); //最后生成的文件路径为 dist/**/*.js
(3)gulp.task(name[, deps], fn)用来定义任务
(A)name 为任务名
(B)deps 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。
(C)fn 为任务函数,我们把任务要执行的代码都写在里面。
(D)gulp.task('mytask', ['array', 'of', 'task', 'names'], function() { //定义一个有依赖的任务 // Do something});
(D)gulp中执行多个任务,可以通过任务依赖来实现。例如我想要执行one,two,three这三个任务,那我们就可以定义一个空的任务,然后把那三个任务当做这个空的任务的依赖就行了:
 //只要执行default任务,就相当于把one,two,three这三个任务执行了
(E)gulp.task('default',['one','two','three']);
(F)如果任务相互之间没有依赖,任务会按你书写的顺序来执行,如果有依赖的话则会先执行依赖的任务。
(G)但是如果某个任务所依赖的任务是异步的,就要注意了,gulp并不会等待那个所依赖的异步任务完成,而是会接着执行后续的任务。
(4)gulp.watch(globs[, opts], tasks)或gulp.watch(glob[, opts, cb])用来监视文件的变化,当文件发生变化后,我们可以利用它来执行相应的任务
(A)globs参数匹配文件路径(路径包括文件名,分为具体路径和通配符路径)。当有多个路径时,该参数为一个数组。
(B)opts 为一个可选的配置对象,通常不需要用到
(C)tasks 为文件变化后要执行的任务,为一个数组
(D)cb参数为一个函数。每当监视的文件发生变化时,就会调用这个函数,并且会给它传入一个对象,该对象包含了文件变化的一些信息,type属性为变化的类型,可以是added,changed,deleted;path属性为发生变化的文件的路径
(E)gulp.watch('js/**/*.js', function(event){
     console.log(event.type); //变化类型 added为新增,deleted为删除,changed为改变
     console.log(event.path); //变化的文件的路径
 });
2、gulp作用
(1)开发:监听、注入(到相关标签)、代理、重载
(2)生产:(从相关标签)导入、分类、压缩、导出
3、gulp中的代理
//实际上,下面(1)(2)两种情况是特殊的http请求,剩下的http请求都是直接向本机发送url
function serveConfig(configDirname) {
  var array = ['/app','/oauth','/status'];//(1)跨域代理:开发过程中,以这些item开始的url,将向后台服务器发送以item开始的url。这种情况主要用于获取动态数据。
  var proxy_ = array.map(function (value) {
    var a = url.parse('https://172.18.10.23' + value);
    a.route = value;
    a.rejectUnauthorized = false;
    return proxy(a);
  });
  browserSync.init(
    {
      port: 8900,
      notify: false,
      open: false,
      server: {
        baseDir: ['src'],
        directory: false,
        index: 'index.html',
        middleware: proxy_,
        routes: {
          '/audit-html/static/img': 'src/img',//(2)本地代理:开发过程中,以key开始的url,将向本地服务器发送以value开始的url。这种情况主要用于获取静态资源,如html文件、css的背景图片和img标签的src属性。
        }
      }
    },
    function () {
      reload();
    }
  );
}
4、在gulp下,建立karma任务
来源:https://www.cnblogs.com/2050/p/4198792.html
var karma = require('karma').server;
gulp.task('test', function(done) {
  karma.start({
    configFile: __dirname + '/tests/my.conf.js',
    singleRun: true
  }, function() {
    done();
  });
});

二、angular项目下index.html文件,
1、index.html注入
<!DOCTYPE html>
<html  ng-controller="mainCtrl">
<head>
</head>
<body ondragstart="return false;">
  <my-app></my-app>
</body>
<script src="/audit-html/static/common/jquery.js"></script>
/* 打包下列文件 */
<!-- build:js(src) scripts/all.min.js --> 
  <!-- inject:js --> 
  /* 默认js文件注入此处 */
  <!-- endinject --> 
  <!-- inject:partials --> 
  /* 特定js文件注入此处 */
  <!-- endinject --> 
<!-- endbuild --> 
</html>
2、gulp打包angular1静态文件的流程----开发环境
(1)监听到有文件变化时,向index.html文件注入css和js文件,渲染,
(2)从上到下执行css文件,
(3)从上到下渲染body,遇到组件,跳过
(4)从上到下执行js文件,遇到异步,跳过,产生依赖模块
(5)执行异步,并将根模块与html文档绑定,给根模块注入依赖,如果有依赖没定义,那么会出错,不会执行config和run
(6)解析组件,这时根组件及其内部组件所需要的html文件,按照指定路径加载,并用run函数定义全局的数据或逻辑
3、gulp打包angular1静态文件的流程----生产环境
(1)将所有的css和js文件,注入到index.html,
(2)将其它的html文件打包成1个js文件,注入到index.html,
(3)将index.html的“所有的css文件”和“所有js文件”打包,插入到另一个index.html里,渲染,
(4)从上到下执行css文件,
(5)从上到下渲染body,遇到组件,跳过
(6)从上到下执行js文件,遇到异步,跳过,产生依赖模块
(7)执行异步,并将根模块与html文档绑定,给根模块注入依赖,如果有依赖没定义,那么会出错,不会执行config和run
(8)解析组件,这时根组件及其内部组件所需要的html文件,从(2)中的js获取,并用run函数定义全局的数据或逻辑
4、执行main.js,在$stateChangeStart事件监听函数里,遇到异步跳过,直奔状态,此时状态对应的配置不存在,页面出错;正确的处理方式为,在权限异步函数的成功回调里,在前端权限列表生成后,再次执行$state.go(),填充到<ui-view>标签里;
5、根模块的依赖模块加载完毕后,根模块挂载到页面上,有如下两种情形
用法一:
<html ng-app="myApp" ng-controller="myCtrl">
  <body></body>
</html>
<script>
  //此处导入依赖['deploy1','deploy2']
  var app = angular.module('myApp', ['deploy1','deploy2']);
  app.controller('myCtrl', function ($scope) { });
</script>
用法二:
<html ng-controller="myCtrl">
  <body></body>
</html>
<script>
  var app = angular.module('myApp', ['deploy1','deploy2']);
  app.controller('myCtrl', function ($scope) { });
  //此处导入依赖['deploy1','deploy2']
  angular.bootstrap(document, ['myApp']);
</script>

三、三大框架之登录、权限、路由嵌套、状态管理、请求响应拦截
1、在angular1中,
(1)权限:在未登录的状态下,刷新浏览器,渲染index.html时,初始化数据,根据$urlRouterProvider.otherwise('/login'),跳转到login状态,触发$stateChangeStart函数,不向后台发送请求,跳转到登录页。登录成功后,向后台发送请求,获取权限信息保存到状态里,建立左侧导航栏和上方选项卡,在sessionStorage里记录登录成功,跳转到首页。后来的页面跳转或刷新浏览器,使用$stateChangeStart拦截,建立上方选项卡。
(2)路由嵌套:<ui-view></ui-view>
(3)状态管理:ui-router
(4)请求响应拦截:$http
(5)跳转示例,$state.go('/firstPage')
$rootScope.$on('$stateChangeStart', function (event, toState) {
  myServer.changeState(event, toState);
}) 
var whiteList = ['login']; 
var islogin = getLoginStage();
if (whiteList.indexOf(toState.name) > -1) return;// 可以拦截
if (islogin) {
  if (roles.length === 0) {
    // 向后台发送请求,获取权限表,建立左侧导航栏和上方选项卡
  } else {
    // 正常访问,建立上方选项卡
  }
}else{
  $state.go('login')
}
2、在vue中,
(1)权限:在未登录的状态下,刷新浏览器,渲染index.html时,初始化数据,执行router.beforeEach,跳转到登录页。登录成功后,向后台发送请求,获取权限信息保存到状态里,建立左侧导航栏和上方选项卡,在sessionStorage里记录登录成功,跳转到首页。后来的页面跳转或刷新浏览器,使用router.beforeEach拦截,建立上方选项卡。
(2)路由嵌套:<router-view></router-view>
(3)状态管理:vuex
(4)请求响应拦截:service.interceptors
(5)跳转示例,this.$router.push({ path: '/firstPage' }),next('/firstPage')
var whiteList = ['/login']; 
var islogin = getLoginStage();
if (islogin) {
  if (store.getters.roles.length === 0) {
    // 向后台发送请求,获取权限表
  } else {
    // 正常访问
  }
} else {
  if (to && whiteList.indexOf(to.path) > -1) {
    next()// 不可以拦截
  } else {
    next(`/login`) 
  }
}
3、在react中,
https://blog.csdn.net/sinat_36728518/article/details/106254395 React-Router4.0以后,路由即组件
(1)权限:在未登录的状态下,刷新浏览器,渲染index.html时,初始化数据,渲染组件FrontendAuth,跳转到登录页。登录成功后,向后台发送请求,获取权限信息保存到状态里,建立左侧导航栏和上方选项卡,在sessionStorage里记录登录成功,跳转到首页。后来的页面跳转或刷新浏览器,渲染组件FrontendAuth,建立上方选项卡。
(2)路由嵌套:{React.Children.map}或{props.children}或<header><Route path="/user" component={UsersMenu}/></header>
(3)状态管理:react-redux
(4)请求响应拦截:service.interceptors
(5)跳转示例,<Redirect to="/login" />;browserHistory.push('/')
<Router>
  <Switch>
    <FrontendAuth routerConfig={routerMap} />
  </Switch>
</Router>
class FrontendAuth extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { routerConfig, location } = this.props;
    const { pathname } = location;
    const targetRouter = routerConfig.find(function(item){
      return item.path === pathname
    });
    const isAuth = targetRouter && targetRouter.auth;
    const isLogin = sessionStorage.getItem("username");
    if (isLogin) {
      if (pathname === "/login") {
        return <Redirect to="/" />;
      } else {
        if (targetRouter) {          //此处建立上方选项卡
          return <Route path={pathname} component={targetRouter.component} />
        } else {
          return <Redirect to="/404"/>;
        }
      }
    } else {
      if(isAuth){
        const { component } = targetRouter;
        return <Route exact path={pathname} component={component} />;
      }else{
        return <Redirect to="/login" />;
      }
    }
  }
}
export default FrontendAuth;

四、环境
1、生产环境:服务器
2、开发环境
(1)前端:node
(2)后台:ubuntu
3、window环境下的上传工具
(1)MobaXterm
(2)xshell
4、ubuntu环境下的上传命令
 scp -r localfile.txt username@192.168.0.1:/home/username/
(1)scp是命令,-r是参数
(2)localfile.txt 是文件的路径和文件名
(3)username是服务器账号
(4)192.168.0.1是要上传的服务器ip地址
(5)/home/username/是要拷入的文件夹路径

五、服务器
1、安装服务器系统
(1)给服务器--插上--系统U盘
(2)重启服务器:拔、插服务器电源(服务器自动安装系统,安装成功时,服务器自动断电)
(3)从服务器--拔掉--系统U盘
(4)再次重启服务器:拔、插服务器电源
2、登陆服务器
(1)用“网线”把“我的电脑”和“服务器”进行物理连接
(2)在“终端工具”上,用“终端工具”的用户名和密码登录“终端工具”
(3)在“终端工具”上,用“服务器”的用户名和密码登录“服务器”
3、给服务器配置IP
(1)root@CyOS:/root# ifconfig mgmt0 192.168.10.156(给接口配置IP。它有65535个端口,ifconfig(配置))mgmt0(接口))
(2)按enter键,IP配置成功
4、启动服务器
(1)root@CyOS:/root# cd /usr/local/audit-web
(2)root@CyOS:/usr/local/audit-web# python manage.py runserver
5、辅助步骤
(1)Ctrl+C(退出进程)
(2)root@CyOS:/usr/local/audit-web# pkill -f python -9(杀死python进程,出现Address already in use时,需要用到这个命令)
(3)root@CyOS:/usr/local/audit-web# pkill -f uwsgi -9(杀死名为uwsgi的进程)
(4)root@CyOS:/usr/local/audit-web# iptables -P INPUT ACCEPT(关闭防火墙,P INPUT ACCEPT均大写)
(5)root@CyOS:/usr/local/audit-web# ps aux|grep python(查看活进程,aux显示所有进程和进程状态,grep在这些里搜索)
(6)root@CyOS:/root# ifconfig(显示或设置网络设备)/////////////////////////
(7)root@CyOS:/root# cat /usr/local/etc/suricata/version.autogen(查看当前版本)
6、通过CMD命令窗口,给本地服务器更新文件的流程
(1)window + r;cmd
(2)ssh root@172.18.58.30,root为登录名
(2-1)SSH(Secure Shell,安全外壳)之所以能够保证安全,原因在于它采用了公钥加密。整个过程是这样的:
(2-2)远程主机收到用户的登录请求,把自己的公钥发给用户。
(2-3)用户使用这个公钥,将登录密码加密后,发送回来。
(2-4)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。
(3)输入密码
(4)wget -O /my.sh "http://192.168.80.152:3000/audit/shell?branch=develop-2.0.8&command=gulp build" && chmod +x /my.sh && /my.sh && rm -f /my.sh
(4-1)-O /my.sh:将下载的文件存储在根目录下并重命名为“my.sh”
(4-2)chmod +x /my.sh:将执行权限赋给根目录下的“my.sh”
(4-3)/my.sh:运行根目录下“my.sh”
(4-4)rm -f /my.sh:删除根目录下“my.sh”
(5)Windows运行CMD常用命令:https://blog.csdn.net/gaofengyan/article/details/89447293
(6)在WINDOWS操作系统里执行CMD命令,可以模拟出DOS操作系统。
7、负载均衡
(1)CDN部署在网络提供商的机房,反向代理部署在网站的机房;
(2)正向代理:客户端通过代理服务器向服务器发送请求,隐藏了真实的客户端;
(3)反向代理:客户端访问代理服务器,代理服务器返回缓存内容,隐藏了真实的服务端;
(4)Nginx:性能非常好的反向代理服务器,用来做负载均衡,可以在Linux系统中运行。
8、IPv4地址(本机ip)
(1)网际协议版本4(Internet Protocol version 4),又称互联网通信协议第四版
(2)IPv4是一种无连接的协议,操作在使用分组交换的链路层(如以太网)上
(3)此协议会尽最大努力交付数据包,意即它不保证任何数据包均能送达目的地,也不保证所有数据包均按照正确的顺序无重复地到达
9、子网掩码和默认网关(缺省网关、路由器)
(1)子网掩码(255.255.240.0)判断目标主机是否在本地子网中,
(2)目标主机在本地子网中,则直接发送
(3)目标主机不在本地子网中,则发送到路由器(默认网关,172.18.10.1),由路由器转发到其他网络中,进一步寻找目标主机。
(4)前后端项目调试的时候,通过代理服务器拼接后台的局域网ip

六、Linux常见命令
1、清除终端内容
(1)ctr+l:终端内容滚到顶部上面            
(2)clear:终端内容滚到顶部上面
(3)reset:清除终端内容
2、ps:显示系统进程
(1)ps -ef:用标准格式显示进程,如ps -ef|grep python 
(2)ps aux:用BSD格式显示进程,如ps aux|grep python
3、cd:进入目录
(1)cd /:进入系统根目录
(2)cd ~:进入用户根目录
(3)cd ../:切换到上一级目录
4、ls:显示本目录下之内容
(1)-a 显示所有文件及目录 (. 开头的隐藏文件也会列出)
(2)-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
(3)-r 将文件以相反次序显示(原定依英文字母次序)
(4)-t 将文件依建立时间之先后次序列出
(5)-A 同 -a ,但不列出 "." (目前目录) 及 ".." (父目录)
(6)-F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加 "/"
(7)-R 若目录下有文件,则以下之文件亦皆依序列出
5、ls -l运行结果说明
示例:drwxr-xr-x 1 qiancheng qiancheng 54713 11月 19 13:08 0.js
(1)文件属性:drwxr-xr-x。d(-文件,d目录)rwx(用户权限)r-x(组用户权限)r-x(其他用户权限);rwx-的含义:r可读,w可写,x可执行,-没有权限
(2)文件硬链接数量:1
(3)所有者:qiancheng(user)
(4)所属用户组:qiancheng(group)
(5)文件大小:54713
(6)修改时间:11月 19 13:08
(7)文件名:0.js(Filename)
6、关于目录的命令
(1)创建目录:mkdir dir
(2)删除目录:rm -rf dir
(3)修改目录:mv oldDir newDir(不存在);
(4)查找目录:find dir -type d;ls;
(5)复制目录:mv oneDir newDir(存在);cp -r oneDir newDir
(6)清空目录:rm -rf dir
7、关于文件的命令  
(1)创建文件:touch aaa.js;cat >> aaa.js
(2)删除文件:rm aaa.js
(3)修改文件:mv aaa.js bbb.js
(4)查找文件:find dir -type f;find dir -name "*.js"  (名为...的文件);find dir -type f -mtime -0.1 -name "*.js" (含0.1天内,更改的文件)
(5)复制文件:cp aaa.js bbb.js
(6)清空文件:> aaa.js;cat /dev/null > aaa.js
8、文件内容查看
(1)nl:显示所有文件内容,并输出行号
(2)cat:由第一行开始显示文件内容
(3)tac:从最后一行开始显示文件内容
(4)less:一页一页的显示文件内容,可以用上下键上下翻页
(5)more:一页一页的显示文件内容,可以往enter键向下翻页
(6)head:只看头几行
(7)tail:只看尾巴几行
9、grep:与字符串相关的搜索
(1)grep "grep" html/*.js
(2)grep "g.\{0,4\}p" html/*.js
(3)grep -i "grep" html/*.js (忽略大小写)
(4)grep -w "grep" html/*.js (搜索整个词)
(5)grep -n "grep" html/*.js (显示行号)
(5)grep -l "grep" html/*.js (只显示文件名)
(6)grep -r "grep" html (递归搜索当前目录及其子目录的全部文件)
(7)grep -v "grep" html/*.js (显示不匹配字串的行)
(8)grep -c "grep" html/*.js (统计匹配的行数)
(9)grep -B 2 "grep" html/*.js (显示之前2行,A后,C前后各)
(10)grep,全局正则表达式输出,global regular expression print */
10、echo:输入字符串
(1)覆盖写入字符串(无引号):echo "字符串" > 1.js
(2)覆盖写入字符串(有引号):echo "\"字符串\"" > 1.js
(3)转义覆盖写入字符串(有引号):echo -e "\"这\n是\n换\n行\"" > 1.js;e开启转义,\n换行,\c:不换行
(4)追加写入字符串:echo "字符串" >> 1.js
11、关机
(1)shutdown:关机
(2)shutdown -t 2:2秒后关机
(3)shutdown -h now:立刻关机
(4)shutdown -h 20:00:20:00关机
(5)shutdown -h +10:10分钟后关机
(6)shutdown -r now:系统立刻重启
(7)shutdown -r +30:30分钟后重启
(8)halt:关机
(9)poweroff:关机
(10)init 0:关机
(11)reboot:重启
12、压缩与解压(解压导出需要加参数)
(1)压缩:tar -czvf file.tar ./aaa/file1;zip html.zip ./aaa
(2)解压:tar -xzvf file.tar -C ./aaa/file2;unzip -d ./aaa file.zip
(3)tar参数之-c建立新的备份文件
(4)tar参数之-x从备份文件中还原文件
(5)tar参数之-z通过gzip指令处理备份文件
(6)tar参数之-v显示指令执行过程
(7)tar参数之-f指定备份文件
(8)unzip参数之-d指定文件解压缩后所要存储的目录
附、其它
(1)打开终端:Ctrl+Alt+T
(2)查看当前目录:pwd

七、Linux一级目录:
来源:https://www.runoob.com/linux/linux-system-contents.html
(1)srv:存放着-服务启动-之后-需要提取-的数据
(2)root:存放着-系统管理员-的主目录
(3)sbin:存放着-系统管理员-使用的-系统管理程序
(4)home:存放着-用户-的主目录
(5)bin: 存放着-用户-的常用命令
(6)boot:存放着-系统启动-时使用的文件
(7)run:存放着-系统启动-以来的信息
(8)etc:存放着-系统管理-所需要的文件
(9)dev:存放着-外部硬件-的设备,包括硬盘,U盘,光驱,串口,打印机等等
(10)media:存放着-自动识别-的设备,比如U盘下的ubuntu
(11)mnt:存放着-临时挂载的-别的文件,比如光驱,进入后可以查看光驱内容
(12)tmp:存放着-临时文件
(13)var:存放着-经常被修改-的文件
(14)opt:存放着-主机-额外安装-的软件,比如搜狗输入法
(15)lib:存放着-动态连接共享库。类似于Windows 里的 DLL 文件
(16)proc:存放着-当前内核-运行状态-的文件
(17)selinux:防火墙,存放selinux相关的文件的
(18)usr:存放着-应用程序。类似于 windows 下的 program files 目录,unix shared resources(共享资源) 的缩写
(18-1)/usr/bin:系统用户使用的应用程序
(18-2)/usr/sbin:超级用户使用的比较高级的管理程序和系统守护程序
(18-3)/usr/src:内核源代码默认的放置目录
附、Linux文件的时间属性
(1)atime:文件内容查看时间,Access time,使用more、cat对该文件进行查看时,atime将更新,ls -lu
(2)mtime:文件内容修改时间,Modify time,使用vi、vim对文件进行修改后保存,mtime将更新,ls -l
(3)ctime:文件属性变更时间,Change time,文件名、内容、大小、权限、所属组等改变时,ctime将更新,ls -lc

八、Linux,ubuntu和VMware
1、三者之间的关系
(1)Linux是一个操作系统;
(2)Ubuntu是一个以桌面应用为主的Linux操作系统
(3)VMware是虚拟主机,在安装的过程中,导入ubuntu
(4)在ubuntu里,应该用Linux命令来操作里面的文件
(5)安装步骤;点击VMware.exe文件直到结束-->点击桌面VMware图标-->点击“创建新的虚拟机”-->安装依赖(最后一步,耗时约40分钟)
(6)4步完全卸载VMware。A、关闭VMware;B、应用卸载-->vmware-->修改-->下一步-->删除;C、C:\Program Files (x86)下删除VMware;D、C:\Users\用户名\Documents下删除Virtual Machines,内含ubuntu 
(7)层级关系:Unix-->Linux-->Debian(得便,自由操作系统)-->Ubuntu
2、Linux的vim编辑器的安装和使用
(1)安装:sudo apt install vim
(2)显示文件内容:vim 路径,如sudo vim ~/.bashrc
(3)命令模式。i 切换到输入模式;: 切换到底线命令模式;x 删除当前光标所在处的字符。
(4)输入模式。ESC 退回命令模式。
(5)底线命令模式。q 退出vim,回到(2)执行前的状态;w 保存文件;字母后面加! 强制。
(6)退出vim。输入模式ESC--命令模式:--底线命令模式q!
3、ubuntu的常见命令和依赖包安装
(1)获取超级用户权限:sudo su
(2)重启虚拟机:sudo reboot
(3)本地安装:sudo dpkg -i package,“dpkg”是“Debian”的包管理器
(4)本地安装:sudo apt install package,“apt”是“Debian”和“Ubuntu”的包管理器
(5)自由安装:wget http://url
(6)层级关系:Unix-->Linux-->Debian(得便,自由操作系统)-->Ubuntu
4、ubuntu实现路径补全
(1)创建文件:touch ~/.pythonrc
(2)添加如下内容:
 import rlcompleter, readline
 readline.parse_and_bind('tab:complete')
(3)在home目录下,.bashrc文件末尾追加如下内容:export PYTHONSTARTUP=~/.pythonrc
(4)更新环境变量:source ~/.bashrc

九、在Ubuntu16.04里,安装搜狗输入法、谷歌浏览器、微信、时间同步、gulp
1、安装简体中文输入法:
(1)设置-系统设置-语言支持-安装-密码-确认-(安装fcitx,耗时约10分钟)
(2)语言-安装/卸载语言-(勾选)中文简体-应用-密码-确认-(安装字体,耗时约10分钟)
(3)区域格式-汉语中国-语言-(汉语中国)拉到第一位-(键盘输入法系统)fcitx-关闭
(4)删除包sudo apt-get remove fcitx-ui-qimpanel
附1:Fcitx是(Free Chinese Input Toy for X)的英文缩写,可为支持 XIM 的 X 应用程序提供输入服务。可以输入UTF-8编码中的汉字。
2、安装搜狗输入法
(1)下载搜狗输入法安装包http://pinyin.sogou.com/linux,进入下载目录cd Downloads
(2)安装搜狗输入法sudo dpkg -i sogoupinyin_2.4.0.3469_amd64.deb
(3)重启虚拟机sudo reboot
(4)文字图标-配置当前输入法-(搜狗输入法个人版)调至第一个选项
3、1和2安装过程中或结束后,可能遇到的问题及解决
问题1:updating cache ; waiting for apt-get to exit
解决1:sudo fuser -vki /var/lib/apt/lists/lock
问题2:由于找不到vcruntime140_1.dll,无法继续执行代码重新安装程序可能会解决此问题
解决2:下载文件vcruntime140_1.dll,复制到32/64位版本电脑的的C:\Windows\system64/32下
问题3:搜狗输入时出现乱码
解决3:killall fcitx
问题4:Windows和Ubuntu16之间不能复制粘贴
解决4:sudo apt-get autoremove open-vm-tools ; sudo apt-get install open-vm-tools-desktop ; Ctrl+c ; sudo reboot
4、安装谷歌浏览器
(1)sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/
(2)wget -q -O - https://dl.google.com/linux/linux_signing_key.pub  | sudo apt-key add -
(3)sudo apt-get update
(4)sudo apt-get install google-chrome-stable
(5)/usr/bin/google-chrome-stable
(6)在屏幕左侧的图标上,右键“锁定到启动器”
5、安装微信(可登陆,2021年11月11日)
(1)安装 deepin-wine:wget -O- https://deepin-wine.i-m.dev/setup.sh | sh
以下主要来源:https://blog.csdn.net/sinat_39369871/article/details/110095705
(2)下载微信安装包:http://packages.deepin.com/deepin/pool/non-free/d/deepin.com.wechat/,点击最后一个
(3)一次运行下列命令(复制以下内容,粘贴到终端,按回车)
#!/bin/bash
mkdir ./deepintemp
cd ./deepintemp
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine/deepin-wine_2.18-22~rc0_all.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine/deepin-wine32_2.18-22~rc0_i386.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine/deepin-wine32-preloader_2.18-22~rc0_i386.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine-helper/deepin-wine-helper_1.2deepin8_i386.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine-plugin/deepin-wine-plugin_1.0deepin2_amd64.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine-plugin-virtual/deepin-wine-plugin-virtual_1.0deepin3_all.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine-uninstaller/deepin-wine-uninstaller_0.1deepin2_i386.deb
wget http://packages.deepin.com/deepin/pool/non-free/u/udis86/udis86_1.72-2_i386.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine/deepin-fonts-wine_2.18-22~rc0_all.deb
wget http://packages.deepin.com/deepin/pool/non-free/d/deepin-wine/deepin-libwine_2.18-22~rc0_i386.deb
wget https://packages.deepin.com/deepin/pool/main/libj/libjpeg-turbo/libjpeg62-turbo_1.5.1-2_amd64.deb --no-check-certificate
wget https://packages.deepin.com/deepin/pool/main/libj/libjpeg-turbo/libjpeg62-turbo_1.5.1-2_i386.deb --no-check-certificate
sudo dpkg --add-architecture i386
sudo apt update
sudo dpkg -i *.deb
sudo apt install -fy
rm -vfr ./deepintemp
(4)安装微信 sudo dpkg -i deepin.com.wechat_2.6.8.65deepin0_i386.deb
6、解决微信不能输入中文的问题
(1)cd /opt/deepinwine/tools/
(2)sudo chmod 777 run.sh  #文件默认为只读,修改权限
(3)vim run.sh   #编辑脚本,加入以下内容:
export GTK_IM_MODULE="fcitx"
export QT_IM_MODULE="fcitx" 
export XMODIFIERS="@im=fcitx"
(4)重启微信,切换为系统自带的fcitx输入法即可输入中文,比如搜狗输入法。
7、系统时间跟本地时间同步
(1)sudo timedatectl set-local-rtc 1
(2)sudo timedatectl set-timezone Asia/Shanghai
(3)data(查看系统时间,可以不执行)
8、全局安装gulp
在ubuntu里,全局安装的gulp才能运行gulp任务,npm全局安装gulp会出错,以下用cnpm安装
(1)sudo  npm install -g cnpm -registry=https://registry.npm.taobao.org
(2)sudo cnpm install -g gulp
(3)gulp

十、electron
1、electron是什么?
(1)用Web技术构建跨平台的桌面应用,electron = Chromium + Node.js + Native API。2016 年 5 月 Electron 发布了 v1.0.0 版本
(2)Chromium,为 Electron 提供了强大的UI能力,可以不考虑兼容性的情况下,利用强大的Web生态来开发界面
(3)Node.js,让 Electron 有了底层的操作能力,比如文件的读写,甚至是集成C++等等操作,并可以使用大量开源的 npm 包来完成开发需求
(4)Native API,Native API 让 Electron 有了跨平台和桌面端的原生能力,比如说它有统一的原生界面,窗口、托盘这些。
2、什么时候使用Electron?
(1)公司没有专门的桌面应用开发者,而需要前端兼顾来进行开发时,用Electron就是一个不错的选择。
(2)一个应用需要同时开发Web端和桌面端的时候,那使用Electron来进行开发就对了。
(3)开发一些效率工具,比如API类的工具。
 
十一、服务端渲染
1、服务端渲染:服务器收到请求后,把数据拼接到html里,发送给浏览器渲染。
2、客户端渲染:服务器收到请求后,发送数据给浏览器,浏览器用js把数据拼接到html里,然后渲染。
3、怎样查看客户端首次渲染:
(1)把http://localhost:8000粘贴到浏览器
(2)打开控制台console
(3)刷新浏览器
 
十二、__dirname|join|resolve
1、__dirname和join
var path = require("path");
console.log(__dirname); c:\Users\公司\Desktop\yuanma
console.log(path.join(__dirname, "..", "src")); c:\Users\公司\Desktop\src
console.log(path.join(__dirname, "../", "src")); c:\Users\公司\Desktop\src
2、__dirname和resolve
var path = require("path");
console.log(__dirname); c:\Users\公司\Desktop\yuanma
console.log(path.resolve(__dirname, "..", "src")); c:\Users\公司\Desktop\src
console.log(path.resolve(__dirname, "../", "src")); c:\Users\公司\Desktop\src
 
十三、npm|cnpm|yarn|tyarn|bootstrap
1、npm:最常用的包管理器。
2、cnpm:是npm的国内镜像。
3、yarn:是2016年重新设计发布的npm客户端,是并行、离线下载的
4、tyarn:是yarn的国内镜像了。
5、npm install 安装命令示例,包名和后面的参数,位置可以互换。
(1)npm install 把package.json中的依赖配置,下载到本地项目的node_modules
(2)npm install X 会把X包安装到项目的node_modules目录中,不会将模块依赖写入package.json中。
(3)npm install X -g 会把X包安装到全局的node_modules目录中,不会将模块依赖写入package.json中。
(4)npm install X --save 会把X包安装到项目的node_modules目录中,会在package.json的dependencies属性下添加X
(5)npm install X --save-dev 会把X包安装到项目的node_modules目录中,会在package.json的devDependencies属性下添加X
6、npm其它命令
(1)npm help <command>可查看某条命令的详情
(2)npm update <package>可以把当前目录下node_modules子目录里边的对应模块更新至最新版本
7、bootstrap
(1)n.[计]辅助程序
(2)vt.启动(电脑)
 
附、webpack
chunk 代码块。
polyfill 兜底。在计算机中,变相实现不能直接实现的操作。
process 对象是一个 global 变量,提供有关当前 Node.js 进程的信息并对其进行控制。
npm与nodejs版本对应关系:https://nodejs.org/zh-cn/download/releases/
dll,动态链接库英文为DLL,是Dynamic Link Library的缩写。(Dynamic,[daɪˈnæmɪk],有活力的)
1、基本知识
(1)安装node环境,nodejs环境变量指的是node环境安装的地方
(2)安装webpack和webpack-cli包
(3)node是运行node文件的命令
(4)npm是node包管理器、npm run start/stop/test可以简写为npm start/stop/test
(5)npm运行的包,必须写入到package.json里面才能运行
(6)npx运行的包,可以在任何地方运行,运行时,从本目录开始逐层向上直至全局(nodejs环境变量)寻找该包,找到就运行,没有找到就临时安装并直接运行,运行结束后删掉;如果想运行层级以外的版本,则加上版本号即可,如npx webpack-dev-server@3.10.3;
(7)直接运行的包,如果本目录或全局安装了该包,可以直接运行,不需要npm和npx,如webpack、webpack-dev-server。
2、开发或生产环境
(1)webpack:是打包的命令,也是模块打包器。将entry输入的文件用module.rules编译打包后,根据mode取值不同而选择压不压缩最终的js,最后通过output把js显性输出到指定目录。
(2)webpack-cli:使webpack命令能(在命令行中)运行,cli即命令行接口(Command Line Interface)。
(3)webpack-dev-server:是开启本地node服务器的命令,也是一个小型的node服务器。将entry输入的文件用module.rules编译打包后,根据mode取值不同而选择压不压缩最终的js,最后通过output把js隐性输出到内存并自动打开浏览器,同时监听entry及其import引入的文件,一旦发生变化就自动编译、打包、隐性输出代码,手动刷新浏览器,可以看到最新效果。
(4)在(1)(3)编译的过程中,根据babel-loader的配置处理js的兼容,根据process.env.NODE_ENV取值不同,选择package.json里browserslist的不同配置项来处理css的兼容问题,根据插件配置决定最终的css压不压缩和输出目录,根据url-loader的配置决定最终的img输出目录和公共路径。
(5)以下webpack.config.js文件示例
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
process.env.NODE_ENV = "development";//打包时使用package.json里browserslist里development配置来处理js/css兼容,即兼容到各浏览器的哪个版本;
module.exports = {
  entry: './src/js/index.js',//引入js,字符串和数组为单入口,对象为多入口;另外对象的value也可以是数组
  output: {
    filename: 'js/built.js',//导出js文件,如果和entry路径的深度不一样,那么webpack会自动调整图片的引用路径
    path: resolve(__dirname, 'build')
  },
  publicPath: '/',// 给所有资源引入公共路径前缀'/',如'imgs/a.jpg'==>'/imgs/a.jpg'
  mode: 'development',//用webpack打包时不压缩,取'production'则压缩
  module: {
    rules: [//loader配置
      {
        test: /\.less$/,// 处理less资源
        use: ['style-loader', 'css-loader', 'less-loader']//从右向左执行
        //'style-loader'开发环境用。在下面的js文件里,隐式地为每个样式文件创建一个style标签并将该样式放入,再将每一个style标签插到head标签里;隐式地自动将output.filename引给JavaScript标签并插入到template里的body标签里。这样head标签里不会有style标签,但控制台里有。
        //'css-loader',将css文件整合到js文件中
        //'less-loader'将less文件转换为css文件
      },
      {
        test: /\.css$/,
        use: [//从下向上执行
          MiniCssExtractPlugin.loader,//提取下面js里的css成单独文件。
          'css-loader',//将css文件整合到js文件中
          {
            loader: 'postcss-loader',//css兼容处理
            /*
              一、css兼容处理:
              1、postcss-loader(提供postcss)
              2、postcss-preset-env(帮postcss找到package.json中browserslist里面的配置,加载指定的css兼容性样式)
              3、package.json中的相关配置
              "browserslist": {
                "development": [//设置node环境变量:process.env.NODE_ENV = "development"
                  "last 1 chrome version",
                  "last 1 firefox version",
                  "last 1 safari version"
                ],
                "production": [//默认是看生产环境
                  ">0.2%",
                  "not dead",
                  "not op_mini all"
                ]
              }
            */
            options: {
              ident: 'postcss',
              plugins: () => [// postcss的插件
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            /*
              开启多进程打包。
              进程启动大概为600ms,进程通信也有开销。
              只有工作消耗时间比较长,才需要多进程打包
            */
            loader: 'thread-loader',
            options: {
              workers: 2 // 进程2个
            }
          },
          {
            loader: 'babel-loader',//js兼容处理
            /*
              二、js兼容处理:
              1、基本兼容处理如箭头函数,用(1)babel-loader(显性使用)(2)@babel/core(隐性支持)(3)@babel/preset-env(显性使用)
              2、复杂兼容处理如promise,除了1以外,还需要用按需加载的(4)core-js(显性使用)或全部引入的(5)@babel/polyfill(显性使用)    
              3、【babel-loader@8 requires Babel 7.x (the package '@babel/core')】
            */
            options: {
              presets: [// 预设:指示babel做怎么样的兼容性处理
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',// 按需加载
                    corejs: {version: 3},// 指定core-js版本
                    targets: {// 指定兼容性做到哪个版本浏览器
                      chrome: '60',
                      firefox: '60',
                      ie: '9',
                      safari: '10',
                      edge: '17'
                    }
                  }
                ]  
              ],
              cacheDirectory: true//开启babel缓存,第二次构建时,会读取之前的缓存
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: resolve(__dirname, 'src'),// 只检查 src 下的js文件
        enforce: 'pre',//2个js匹配,这个优先执行。也可以像处理css文件那样,把2个包放到1个use数组里。延后执行'post'
        loader: 'eslint-loader',
        /*
          三、js语法检查:
          1、eslint-loader(显性使用) eslint(隐性支持),eslint-config-airbnb-base(隐性支持) eslint-plugin-import(隐性支持)
          2、package.json中的相关配置
          "eslintConfig": {
            "extends": "airbnb-base"
          }
          3、//eslint-disable-next-line,下一行所有eslint规则都失效
        */
        options: {
          fix: true// 自动修复eslint的错误
        }
      },
      {
        test: /\.(jpg|png|gif)$/,// 处理.css中的图片
        loader: 'url-loader',//在.css中的图片,通过css-loader存储到js文件中,在js文件里改名后,可根据图片大小将图片转码为base64保存在js中或用common.js(默认用ES6,在配置中被esModule:false关闭)模块导出。js里存储了图片改前名和改后名的关联,后来再用到这张图片时会用到这个关联。
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          esModule: false,// 关闭es6模块化
          outputPath: "img",
          publicPath: "/img",
        }
      },
      {
        test: /\.html$/,// 处理html中的图片
        loader: 'html-loader'//在.html文件img标签中的图片,用common.js模块处理,从而能被url-loader进行处理。
      },
      {
        exclude: /\.(html|js|css|less|jpg|png|gif)/,// 处理其他资源
        loader: 'file-loader',//原封不动地输出文件
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media',
          publicPath: "/media",
        },
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.css'//导出css文件。默认配置为filename: './main.css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),//对上面导出的css进行压缩
    new HtmlWebpackPlugin({//将导出的js文件或css文件插入到html文件head-link里或body-script里
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,//去除index.html里面的空白
        removeComments: true//去除index.html里面的注释
      }
    }),
    new webpack.NamedModulesPlugin(), // 告知哪个文件被热替换(非必需)
    new webpack.HotModuleReplacementPlugin(), // 热替换插件
    new WorkboxWebpackPlugin.GenerateSW({
      /*
        1. 帮助serviceworker快速启动
        2. 删除旧的 serviceworker
        生成一个 serviceworker 配置文件~
      */
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  devServer: {//开发环境必有
    compress: true,// 启动gzip压缩
    contentBase: resolve(__dirname, 'build'),// 告诉服务器内容的来源。仅在需要提供静态文件时才进行配置。
    watchContentBase: true,// 监视 contentBase 目录下的所有文件,一旦文件变化就会 reload
    watchOptions: {
      ignored: /node_modules/// 忽略文件
    },
    port: 5000,// 端口号
    host: 'localhost',// 域名
    open: true,// 自动打开浏览器
    hot: true,// 开启HMR功能,需要插件webpack.HotModuleReplacementPlugin配合
    proxy: {// 服务器代理 --> 解决开发环境跨域问题
      '/api': {// 一旦服务器5000接收到'/api/xxx'的请求
        target: 'http://localhost:3000',//就会把请求转发到另外一个服务器3000
        pathRewrite: {// 发送请求时,请求路径重写:将/api去掉
          '^/api': ''
        }
      }
    },
    clientLogLevel: 'none',// 不要显示启动服务器日志信息
    quiet: true,// 除了一些基本启动信息以外,其他内容都不要显示
    overlay: false,// 如果出错了,不要全屏提示~
  },
  devtool: "nosources-source-map",//正常情况下,此配置项缺失比加上更好
  resolve: {// 解析模块的规则
    alias: {// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
      $css: resolve(__dirname, 'src/css')
    },
    extensions: ['.js', '.json', '.jsx', '.css'],// 配置省略文件路径的后缀名
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']// 告诉 webpack 解析模块是去找哪个目录
  }
  optimization: {
    /*
      1. 可以将node_modules中(除dll外)代码单独打包一个chunk最终输出
      2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
    */
    splitChunks: {
      chunks: 'all'
    }
  },
  externals: {//用CDN时,需要此项配置;用dll时不能有此项配置。
    jquery: "jquery", // 不打包第三方类库jquery
    vue: "vue", // 不打包第三方类库vue
  },
};
3、工程化优化之HMR,热模块替换。
(1)当webpack-dev-server运行时,不使用HMR,一个模块发生改变,所有模块都重新打包,最后浏览器重新渲染;使用HMR,一个模块发生改变,只会重新打包这一个模块,最后浏览器重新(请求)渲染。
(2)不采用尚硅谷的热模块方案,因为里面讲的是原理,当监听到变化时,执行的是函数,而不是打包和刷新。另外,后来我在写配置文件时,开发环境和生产环境,都用MiniCssExtractPlugin.loader,不用'style-loader'。
(3)采用热模块的正常方案,A、new webpack.NamedModulesPlugin(),获取热模块的模块名;B、new webpack.HotModuleReplacementPlugin()打包热模块
(4)没有重新请求的渲染不会导致控制台以前的数据丢失。
4、工程化优化之使用缓存
(1)通常情况下,在本地打包前端所有文件,然后上传给远端服务器的最终目录,替换掉原来的前端文件。这个替换时间比较长,有可能影响正常的网站访问。
(2)一般情况下,将改动的某个前端文件上传给远端服务器的临时目录,当只有js/css文件发生改变时,只打包js/css文件到最终目录里,在最终目录里,用最新的js/css文件名替换掉index.html上原来的文件名,这个替换时间比较短,同时删掉原来的js/css文件。
(3)使用缓存时,文件命名规则{filename: "js/built.[contenthash:10].js"/"css/built.[contenthash:10].css"}
5、工程化优化之去除无用代码
(1)tree shaking,摇树优化
(2)前提:必须使用ES6模块化、开启production环境
(3)作用: 减少代码体积
(4)在package.json中配置
  "sideEffects": false//所有代码都没有副作用(都可以进行tree shaking)  
  "sideEffects": ["*.css","*.less"]//.css、.less不要优化,因为优化可能会把@babel/polyfill文件删掉
6、工程化优化之多入口
(1)有多个入口、有多个输出、index.html有多个注入
示例
entry: {
  index: './src/js/index.js',
  test: './src/js/test.js'
},
(2)入口文件为单入口,但文件内部通过import动态导入语法,能将某个文件单独打包
(3)optimization:见上面配置项optimization
{
  /*
    1. 可以将node_modules中(除dll外--自悟)代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  splitChunks: {
    chunks: 'all'
  }
},
7、工程化优化之PWA
(1)渐进式网络应用,可离线访问,英文为“Progressive Web App”,见上面插件WorkboxWebpackPlugin。
(2)eslint不认识 window、navigator全局变量。解决:需要修改package.json中eslintConfig配置
  "env": {
    "browser": true // 支持浏览器端全局变量
  }
(3)普通js文件  
  if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw注册成功了~');
      })
      .catch(() => {
        console.log('sw注册失败了~');
      });
  });
}
8、工程化优化之dll
(1)对第三方库单独打包,如:jquery、react、vue...
(2)webpack.dll.js文件说明,用变量生成映射库
module.exports = {
  entry: {
    jquery: ["jquery"],
    vue: ["vue"],
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // 打包库里向外文件的名称
  },
  plugins: [
    new webpack.DllPlugin({ // 生成映射库
      name: "[name]_[hash]", // 映射库里文件的名称
      path: resolve(__dirname, "dll/manifest_[name].json"), // 输出多个文件时,文件名用变量
    }),
  ],
  mode: 'development'
};
(3)webpack.config.js文件说明,用列举使用映射库
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new webpack.DllReferencePlugin({// 使用映射库,把依赖的名称映射到built.js里模块的id上
      manifest: resolve(__dirname, "dll/manifest_jquery.json"),
    }),
    new webpack.DllReferencePlugin({// 使用映射库,把依赖的名称映射到built.js里模块的id上
      manifest: resolve(__dirname, "dll/manifest_vue.json"),
    }),
    new AddAssetHtmlWebpackPlugin([// 添加资源库,将资源打包出去,并在html中自动引入
      { filepath: resolve(__dirname, "dll/jquery.js") },// 有多项时,用数组
      { filepath: resolve(__dirname, "dll/vue.js") },// 只有一项时,直接用对象即可
    ]),
  ],
  mode: 'development',
};
9、其它优化方法
(1)oneOf:[],只执行数组选项中的一个
(2)将多次使用的加载器放到一个数组里,供展开使用
(3)懒加载,当需要使用文件时才加载,比如点击某个按钮后才加载某个文件
(4)多进程:见上面配置thread-loader
(5)不打包第三方类库:用externals排除第三方类库,用CND引入第三方库
10、package.json重要插件
{ 
  "babel-core": "6.26.0",//把ES6+换为ES5的核心插件
  "babel-preset-es2015": "^6.24.1",//2017年Babel宣布ES2015/ES2016/ES2017被废弃
  "babel-preset-env": "^1.7.0",//根据配置的目标浏览器或运行环境,自动将ES2015+转换为ES5。
  "babel-loader": "7.1.5",//将ES2015+转换为ES5。
  "babel-eslint": "8.2.6",//ES6+语法检测。
  "url-loader": "1.0.1",//将引⼊的图⽚以base64编码并打包到⽂件中,最终只需要引⼊这个dataURL就能访问图⽚了。
  "vue-loader": "15.3.0",//解析和转换.vue文件,提取出其中的逻辑代码script、样式代码style、以及HTML模版template,再分别把它们交给对应的 Loader 去处理。
  "vue-style-loader": "4.1.2",//除了支持客户端渲染,还支持服务端渲染
}