13、gulpAPI、介绍、开发流程、打包流程,angular1项目总逻辑、三大框架之登录和权限的逻辑、angular项目下index.html的注入与执行,

178 阅读24分钟

13、gulpAPI、介绍、开发流程、打包流程,angular1项目总逻辑、三大框架之登录和权限的逻辑、angular项目下index.html的注入与执行,换肤、gulpfile.js、服务器系统安装、主机给服务器配置IP、主机开启服务器、Linux基础、Linux常用命令介绍、electron、服务端渲染、客户端渲染、webpack用法与示例、__dirname|join|resolve

一、gulpAPI
1gulp.src(globs[, options])导入文件的路径
(1globs参数匹配文件路径(路径包括文件名,分为具体路径和通配符路径)。当有多个路径时,该参数为一个数组。
(2options为可选参数。通常情况下我们不需要用到。
(3)* 匹配文件路径中的0个或多个字符,但不会匹配路径分隔符,除非路径分隔符出现在末尾
(4)** 匹配路径中的0个或多个目录及其子目录,需要单独出现,即它左右不能有其他东西了。如果出现在末尾,也能匹配文件。
(5gulp.src(['js/*.js','css/*.css','*.html'])
(6)使用数组的方式还有一个好处就是可以很方便的使用排除模式,在数组中的单个匹配模式前加上!即是排除模式,它会在匹配的结果中排除这个匹配,要注意一点的是不能在数组中的第一个元素中使用排除模式
(7gulp.src([*.js,'!b*.js']) //匹配所有js文件,但排除掉以b开头的js文件8gulp.src(['!b*.js',*.js]) //不会排除任何文件,因为排除模式不能出现在数组的第一个元素中
2gulp.dest(path[,options])导出文件的目录
(1path为写入文件的路径
(2options为一个可选的参数对象,通常我们不需要用到
(3gulp.dest()传入的路径参数,只能用来指定要生成的文件的目录,生成的文件名是由导入到它的文件流决定的。
(4gulp.dest(path)生成的文件路径是我们传入的path参数后面再加上gulp.src()中有通配符开始出现的那部分路径。例如:
(5gulp.src('script/**/*.js') .pipe(gulp.dest('dist')); //最后生成的文件路径为 dist/**/*.js
3gulp.task(name[, deps], fn)用来定义任务
(1name 为任务名
(2deps 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。
(3fn 为任务函数,我们把任务要执行的代码都写在里面。
(4gulp.task('mytask', ['array', 'of', 'task', 'names'], function() { //定义一个有依赖的任务 // Do something});5gulp中执行多个任务,可以通过任务依赖来实现。例如我想要执行one,two,three这三个任务,那我们就可以定义一个空的任务,然后把那三个任务当做这个空的任务的依赖就行了:
 //只要执行default任务,就相当于把one,two,three这三个任务执行了6gulp.task('default',['one','two','three']);
(7)如果任务相互之间没有依赖,任务会按你书写的顺序来执行,如果有依赖的话则会先执行依赖的任务。
(8)但是如果某个任务所依赖的任务是异步的,就要注意了,gulp并不会等待那个所依赖的异步任务完成,而是会接着执行后续的任务。
4gulp.watch(globs[, opts], tasks)或gulp.watch(glob[, opts, cb])用来监视文件的变化,当文件发生变化后,我们可以利用它来执行相应的任务
(1globs参数匹配文件路径(路径包括文件名,分为具体路径和通配符路径)。当有多个路径时,该参数为一个数组。
(2opts 为一个可选的配置对象,通常不需要用到
(3tasks 为文件变化后要执行的任务,为一个数组
(4cb参数为一个函数。每当监视的文件发生变化时,就会调用这个函数,并且会给它传入一个对象,该对象包含了文件变化的一些信息,type属性为变化的类型,可以是added,changed,deletedpath属性为发生变化的文件的路径
(5gulp.watch('js/**/*.js', function(event){
     console.log(event.type); //变化类型 added为新增,deleted为删除,changed为改变
     console.log(event.path); //变化的文件的路径
 });

二、gulp介绍
1gulp自动化工具的作用:
(1)打包,供生产环境使用。
(2)监听,供开发环境使用。
2gulp自动化工具的数据来源:
(1)请求静态资源时,通过配置指向本机;
(2)请求动态数据时,通过配置指向服务器。
(3)生产环境下,所有的数据都按照代码里面的url获取
3、在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();
  });
});
4gulpfile.js
var fs = require('fs');
var url = require('url');
var gulp = require('gulp');
var Gaze = require('gaze').Gaze;
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;
var proxy = require('proxy-middleware');
var getGulpPlugin = require('gulp-load-plugins')();
var runSequence = require('run-sequence');

三、gulp开发流程
gulp.task('default', function () {
  testServe('cy', 'cy');
});
function testServe(moduleDirName, configDirname) {
  //(1)向index.html里注入js(含被压缩成js的html)、css
  injectAndReload(moduleDirName, configDirname);
  //(2)监听各路径下文件的增减和文件内容的改变
  gaze && gaze.close();
  browserSync && browserSync.exit();
  gaze = new Gaze('src/**/*');
  gaze.on('all', function () {
    injectAndReload(moduleDirName, configDirname);
  });
  //(3)代理请求并重新加载index.html
  var myProxy = [    '/app',    '/global',    '/logio',  ].map(function (value) {
    var a = url.parse('http://192.168.80.152:7300'+value);
    a.route = value;
    return proxy(a);
  });
  browserSync.init({
      port: 8900,
      notify: false,
      open: false,
      server: {
        baseDir: ['src'],//开发过程中,需要的所有文件都应该放在src文件夹下,尤其是某状态的html文件
        directory: false,
        index: 'index.html',
        middleware: myProxy,
        routes: {
          '/audit-html/static/img': 'src/img',//服务器存放文件的路径:本地开发时存放文件的路径
          '/config/project/static/img': 'src/img'
        }
      }
    },
    function () { reload(); }
  );
}
function injectAndReload(moduleDirName, configDirname) {
  var jsArray = getJsCssHtml(configDirname).js;
  var cssArray = getJsCssHtml(configDirname).css;
  var htmlArray = getJsCssHtml(configDirname).tpl;
  gulp.src(htmlArray)
    .pipe($.htmlmin({collapseWhitespace: true,removeComments: true,minifyCSS: true}))//将html连同它所在的文件夹一起抽出,并进行最基本的压缩(去空格、去注释)
    .pipe($.angularTemplatecache({module: 'app'}))//将各文件夹里的HTML按照路径合并到一个js文件里,并缓存到app模块里
    .pipe(gulp.dest('template'));//导出js文件,下面与其它js拼接时,放在最后 
  var array = jsArray.concat(cssArray,['template/htmlJS.js']);
  gulp.src('src/tpl/index.html')
    .pipe($.inject(gulp.src(array), {relative: true}))//注入区域为<!-- inject:js --> <!-- endinject -->
    .pipe(gulp.dest('src/'))
    .on('end', reload);
}

四、gulp打包流程
// 引进的类库只打包不压缩,自己写的文件既打包又压缩。
// 打包后的文件,在开发时都存放在文件夹dist下,
// 在生产时都放在文件夹/audit-html/static/下;
// 生产页面index.html在生产时,放在audit-html/template下
gulp.task('build', function () {
  gulp.src(['tmp', 'dist', 'rev']).pipe(clean());//清除文件夹内容,为本次打包腾地方
  gulp.src(paths).pipe(gulp.dest('dist/img'));//导出图片,供页面加载时使用
  gulp.src(['src/vendor/common-vendor/**'])
    .pipe(gulp.dest('dist/common'));//导出类库,供生产页面index.html的<link href="">和<script src=""></script>引用
  gulp.src(['src/brows/*']).pipe(gulp.dest('dist/brows'));//导出浏览器,供交互时返回
  gulp.src(['src/index.html'])//打包index.html里<!-- build:js scripts/all.min.js --><!-- endbuild -->之间的资源
    .pipe($.useref())//将html进行合并。
    .pipe($.if('*.js', $.ngAnnotate()))//解决angular中,依赖注入出错的问题 
    .pipe($.if('*.js', $.uglify()))//压缩js
    .pipe($.if('*.css', $.cleanCss()))//压缩css
    .pipe(gulp.dest('dist'));//导出文件为'dist/scripts/all.min.js',由注释标签里的内容决定
  gulp.src(['./dist/style/all.min.css', './dist/script/all.min.js'])//添加hash后缀,避免新旧文件混淆
    .pipe(rev())//添加hash后缀
    .pipe(gulp.dest('./dist'))//导出文件为'dist/styles/all_34543.min.css'和'dist/styles/all_abcba.min.css',供生产页面index.html的<link href="">和<script src=""></script>引用
  gulp.src(['dist/scripts/all.min.js','dist/styles/all.min.css','dist/index.html'])//删除临时文件,只留将上线的文件
    .pipe(clean());//删除上面三个文件
});

五、angular1项目总逻辑
1angular模块,angular项目必须先定义模块,比如在module文件夹下,有appservercomponentpage1page2...等文件夹,
(1)在app文件夹下定义根模块(app)、普通模块(servercomponentpage1page2)、全局方法,
(2)在server文件夹下获取server模块,在该模块上定义各种各样的服务,比如请求服务,里面只有js文件
(3)在component文件夹下获取component模块,在该模块上定义各种各样的组件,比如整体页面组件、分页组件,里面有htmlcssjs文件
(4)在page1page2文件夹下获取page1page2模块,在该模块上定义各自的选项卡页面,里面有htmlcssjs文件
2src文件夹存放所有开发资源和开发任务,下有index.html文件,moduleimgbrowsercommon文件夹,common文件夹存放外来框架、类库。src文件夹外存放打包结果、说明文档。
3angular服务,必须先注入到configruncontroller里,然后才能使用。

六、三大框架之登录和权限的逻辑
1、在angular1中,
$rootScope.$on('$stateChangeStart', function (event, toState) {
    myServer.changeState(event, toState);
    //changeState检验登陆状态
    //页面加载完毕,直接跳往登录页,登录成功后,获取用户信息,再跳往首页,根据登陆标志,向后台请求,获取权限信息,比如导航栏和选项卡,改变登陆标志。后来页面跳转时,用状态改变函数拦截,根据登陆标志,直接建选项卡。
  })  
(1)登录:在config里执行,$urlRouterProvider.otherwise('/login'),触发$stateChangeStart2)权限:登录成功后,设置标志,跳转到另一状态(页面),触发 $stateChangeStart
2、在vue中,
(1)登录:渲染index.html时,跳转到path: '/',执行router.beforeEach,检查是否登录;沒登录则跳转到path: '/login';
(2)权限:登录成功后,设置标志,跳转到path: '/',再次执行router.beforeEach;向后台获取权限信息。
3、在react中,
(1)登录:渲染index.html时,跳转到path: '/',执行dispatch action,检查是否登录;沒登录则跳转到path: '/login';
(2)权限:登录成功后,设置标志,跳转到path: '/',再次执行dispatch action;向后台获取权限信息。
4、导航、选项卡、页内按钮权限添加完毕后,进行无权限调试
(1)导航:if(条件)改为if(true)
(2)选项卡:维持原样
(3)页内按钮:在检验是否登陆的逻辑里,定义account_data.all_roles.indexOf = function () { return true;};
(4)其它数据,比如登录名、角色等,随意
(5)以上操作均在stateChange函数里
(6)点击登录时,直接跳转正在调试的那个状态

七、angular项目下index.html的注入与执行,
1、生产页面
<!DOCTYPE html>
<html lang="en" ng-controller="mainCtrl" ng-cloak>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
    <title ng-bind="r_g_company.info.title"></title>
    <link rel="shortcut icon" ng-href="{{r_g_company.info.favicon}}"/>
    <link rel="stylesheet" href="/audit-html/static/common/bootstrap.css"/>
    <link rel="stylesheet" href="/audit-html/static/common/editor.md/css/editormd.min.css"/>
    <link rel="stylesheet" href="/audit-html/static/common/animate.min.css"/>
    <link rel="stylesheet" href="/audit-html/static/styles/all_73567.min.css"/>
  </head>
  <body ondragstart="return false;">
    <my-app></my-app>
  </body>
  <script src="/audit-html/static/common/jquery.js"></script>
  <script src="/audit-html/static/common/jquery-media.js"></script>
  <script src="/audit-html/static/common/echart.js"></script>
  <script src="/audit-html/static/common/webuploader.js"></script>
  <script src="../../static/scripts/all_yhg.min.js"></script>//回退一次就到根目录/audit-html了,再回退则忽略
</html>
2index.html注入前页面
<!DOCTYPE html>
<html lang="en" ng-controller="mainCtrl" ng-cloak>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title ng-bind="r_g_company.info.title"></title>
<link rel="shortcut icon" ng-href="{{r_g_company.info.favicon}}">
<link rel="stylesheet" href="/audit-html/static/common/bootstrap.css">
<link rel="stylesheet" href="/audit-html/static/common/sliderCaptcha/slidercaptcha.css">
<!-- build:css(src) styles/all.min.css --> 下面的css将被打包
<!-- inject:css --> css将注入到下面
<link rel="stylesheet" href="module/policy/cy/policy-flow-watch.css">
<link rel="stylesheet" href="module/policy/cy/policy-Anti-attack.css">
<!-- endinject --> css将注入到上面
<!-- endbuild --> 上面的css将被打包
</head>
<body ondragstart="return false;">
  <my-app></my-app>
</body>
<script src="/audit-html/static/common/jquery.js"></script>
<script src="/audit-html/static/common/select.js"></script>
<!-- build:js(src) scripts/all.min.js --> 下面的js将被打包
<!-- inject:js --> js将注入到下面
<script src="config/main.js"></script>
<script src="module/role/cy/role-manage.js"></script>
<!-- endinject --> js将注入到上面
  <!-- inject:partials --> 特定js将注入到下面
  <!-- angular templates will be automatically converted in js and inserted here -->
  <!-- endinject --> 特定js将注入到上面
<!-- endbuild --> 上面的js将被打包
</html>
3index.html注入后页面
<!DOCTYPE html>
<html lang="en" ng-controller="mainCtrl" ng-cloak>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <title ng-bind="r_g_company.info.title"></title>
  <link rel="shortcut icon" ng-href="{{r_g_company.info.favicon}}">
  <link rel="stylesheet" href="/audit-html/static/common/bootstrap.css">
  <link rel="stylesheet" href="/audit-html/static/common/sliderCaptcha/slidercaptcha.css">
  <link rel="stylesheet" href="/audit-html/static/common/editor.md/css/editormd.min.css">
  <link rel="stylesheet" href="/audit-html/static/common/animate.min.css">
  <link rel="stylesheet" href="/audit-html/static/common/angular.treeview.css">
  <link rel="stylesheet" href="/audit-html/static/common/nprogress/nprogress.css">
  <!-- build:css(src) styles/all.min.css -->
  <!-- inject:css -->
  <link rel="stylesheet" href="module/common-css/animate.css">
  <link rel="stylesheet" href="module/common-css/boot-reset.css">
  <link rel="stylesheet" href="module/common-css/bower.css">
  <!-- endinject -->
  <!-- endbuild -->
</head>
<body ondragstart="return false;">
  <my-app></my-app>
</body>
<script src="/audit-html/static/common/jquery.js"></script>
<script src="/audit-html/static/common/jquery-media.js"></script>
<script src="/audit-html/static/common/sliderCaptcha/longbow.slidercaptcha.js"></script>
<script src="/audit-html/static/common/angular.js"></script>
<script src="/audit-html/static/common/angular-ui.js"></script>
<!-- build:js(src) scripts/all.min.js -->
<!-- inject:js -->
<script src="config/main.js"></script>
<script src="config/ctrl.js"></script>
<script src="config/project/cy/logo.js"></script>
<script src="config/project/cy/menu.js"></script>
<script src="module/common-serve/data-g.js"></script>
<script src="module/common-serve/date.js"></script>
......
<script src="module/role/cy/role-source.js"></script>
<!-- endinject -->
  <!-- inject:partials -->
  <!-- angular templates will be automatically converted in js and inserted here -->
  <!-- endinject -->
<!-- endbuild -->
</html>
4index.html中,js文件从上到下执行
(1)执行main.js,
(A)注入依赖,当缓存中没有依赖key1时,记依赖对象为{key1:null,key2:null,...},
(B)执行config(在模块初始化时对模块进行配置)和run(只在angular项目启动的时候运行一次,定义全局的数据或逻辑)
(2)执行main.js文件下面的js文件,当key1出现时,key1修改依赖对象为{key1:value1,key2:value2,...},
(3)所有js文件执行完毕以后,如果key1也没有出现,则会报错,不会执行configrun的参数,否则会执行。
注:每个Angular“应用程序”ng-app都有一个 injector ,负责创建并查找依赖。
(4)在index.js中定义组件myApp
(function () {
  angular
    .module('common-dir', [])
    .directive('myApp', function () {
      console.log('myApp');
      var dirAlert = '<dir-alert></dir-alert>';
      var dirCommon = '<dir-common style="height:100%"></dir-common>';
      var dirTip = '<dir-tip></dir-tip>';
      var dirLoading = '<dir-load></dir-load>';
      var template = ''.concat(dirCommon, dirAlert, dirTip, dirLoading);
      return {
        restrict: 'E',
        template: template,
        scope: false,
        link: function () { }
      };
    });
})();
(5)在main.js中定义模块app
(function () {
  angular
    .module('app', [
      'ui.router',
      'angularTreeview',
      'common-serve',
      'module-login',
      'module-role',
    ])
    .config(function ($stateProvider, $urlRouterProvider, menu) {
      angular.forEach(menu, function (item) {
        angular.forEach(item.subs, function (it) {
          $stateProvider
            .state(it.state, it.cfg);
        });
      });
      $urlRouterProvider.otherwise('/login');
    })
    .run(function ($rootScope, account_m, app_init, account_data) {
      app_init
        .size_init()
        .key_init()
        .account_init();
      $rootScope.$on('$stateChangeStart',
        function (event, toState) {
          NProgress.start();
          account_m.start(event, toState);
        }
      );
      $rootScope.$on('$stateChangeSuccess',
        function (event, toState) {
          account_data.state = toState.name;
          NProgress.done();
        }
      );
    });
})();

八、换肤
(function () {
  function startAppBuild(config) {
    angular
      .module('app')
      .value('company', config);
    angular.bootstrap(document, ['app']);
  }
  $.get('/settings/setting.json?' + new Date().getTime(), {})
    .then(function (settings) {
      var config = settings
      startAppBuild(config);
    })
})();

九、webpack
chunk 代码块。
polyfill 兜底。在计算机中,变相实现不能直接实现的操作。
process 对象是一个 global 变量,提供有关当前 Node.js 进程的信息并对其进行控制。
npmnodejs版本对应关系:https://nodejs.org/zh-cn/download/releases/
1、基本知识
(1)安装node环境,nodejs环境变量指的是node环境安装的地方
(2)安装webpackwebpack-cli包
(3node是运行node文件的命令
(4npmnode包管理器、npm run start/stop/test可以简写为npm start/stop/test5npm运行的包,必须写入到package.json里面才能运行
(6npx运行的包,可以在任何地方运行,运行时,从本目录开始逐层向上直至全局(nodejs环境变量)寻找该包,找到就运行,没有找到就临时安装并直接运行,运行结束后删掉;如果想运行层级以外的版本,则加上版本号即可,如npx webpack-dev-server@3.10.3;
(7)直接运行的包,如果本目录或全局安装了该包,可以直接运行,不需要npmnpx,如webpackwebpack-dev-server2、开发或生产环境
(1webpack:是打包的命令,也是模块打包器。将entry输入的文件用module.rules编译打包后,根据mode取值不同而选择压不压缩最终的js,最后通过outputjs显性输出到指定目录。
(2webpack-cli:使webpack命令能(在命令行中)运行,cli即命令行接口(Command Line Interface)。
(3webpack-dev-server:是开启本地node服务器的命令,也是一个小型的node服务器。将entry输入的文件用module.rules编译打包后,根据mode取值不同而选择压不压缩最终的js,最后通过outputjs隐性输出到内存并自动打开浏览器,同时监听entry及其import引入的文件,一旦发生变化就自动编译、打包、隐性输出代码,手动刷新浏览器,可以看到最新效果。
(4)在(1)(3)编译的过程中,根据babel-loader的配置处理js的兼容,根据process.env.NODE_ENV取值不同,选择package.jsonbrowserslist的不同配置项来处理css的兼容问题,根据插件配置决定最终的css压不压缩和输出目录,根据url-loader的配置决定最终的img输出目录和公共路径。
(4)以下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中代码单独打包一个chunk最终输出
      2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
    */
    splitChunks: {
      chunks: 'all'
    }
  },
  externals: {
    // 拒绝jQuery被打包进来
    jquery: 'jQuery'
  },
};
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、工程化优化之去除无用代码
(1tree 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动态导入语法,能将某个文件单独打包
(3optimization:见上面配置项optimization
7、其它优化方法
(1oneOf:[],只执行数组选项中的一个
(2)将多次使用的加载器放到一个数组里,供展开使用
(3)懒加载,当需要使用文件时才加载,比如点击某个按钮后才加载某个文件
(4PWA: 渐进式网络应用,可离线访问,英文为“Progressive Web App”,见上面插件WorkboxWebpackPlugin5)多进程:见上面配置thread-loader6)不打包:externals7dll:对第3方库进行单独打包

十、服务器系统安装
1、通过FTP下载bin包至系统U盘
(1)地址:192.168.80.892)用户名:cy-version3)密码:cy8888884bin包存放路径:/versions/INA/INA-V2.0.4/
(5)下载bin包并存放至系统U2、给服务器--“插上--系统U盘”
3、重启服务器(拔、插--电源,系统会自动安装成功,此过程耗时较长,点击COM3可以观看安装进程,出现OK和绿星,表示安装成功,此时服务器会“自动断电”)
4、给服务器--“拔掉--系统U盘”
5、重启服务器(拔、插--电源)

十一、主机给服务器配置IP
1、“打开Xshell”,点击COM3,把我的电脑和服务器连接起来
2、按enter键
3、CyOS login: admin
4Password:changyang123!@#
5、CyOS# start
6Password:Cy@508#(此步骤后,可以查看当前版本)
  --------------------------------------------------
7、root@CyOS:/root# ifconfig mgmt0 192.168.10.156(给接口配置IP。它有65535个端口,ifconfig(配置)、mgmt0(接口))
8、按enter键,IP配置成功
9、关闭Xshell

十二、主机开启服务器
1、“打开Xshell”
2、点击http://192.168.10.156:5000(后台程序员已经将资源放到5000端口里)
3、弹窗输入admin
4、弹窗输入changyang123!@#
5、CyOS# start(-shell)
6Password:Cy@508# (http://192.168.10.59,到此为止即可登录,不需下面操作===================)
  --------------------------------------------------
  以下审计
7、root@CyOS:/root# cd /usr/local/audit-web
8、root@CyOS:/usr/local/audit-web# python manage.py runserver(启动服务)
  --------------------------------------------------
  以下南网
7、root@CyOS:/root# cd utils
8、root@CyOS:/root/utils# ./debug.sh 
9、root@CyOS:/root/utils# iptables -P INPUT ACCEPT
10、root@CyOS:/root/utils# iptables -A INPUT -i mgmt0 -p tcp --destination-port 5000 -j ACCEPT
11、root@CyOS:/root/utils# /usr/local/nanwang-py-env/env/bin/python2.7  /usr/local/nanwang-proj/web/manage.py
附1、辅助步骤
(1)Ctrl+C(退出进程)
(2)root@CyOS:/usr/local/audit-web# pkill -f python -9(杀死python进程,在四18)后出现“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(查看当前版本)
(8)服务器重启:(1192.168.10.59不会丢失IP;(2192.168.10.156:5000会丢失ip;(3)经过在审计项目进行如下操作“设置-IP设置-设置本机IP-192.168.10.156-255.255.255.0-192.168.10.1”后,ip不会丢失。

十三、相关知识
1、负载均衡
(1)CDN部署在网络提供商的机房,反向代理部署在网站的机房;
(2)正向代理:客户端通过代理服务器向服务器发送请求,隐藏了真实的客户端;
(3)反向代理:客户端访问代理服务器,代理服务器返回缓存内容,隐藏了真实的服务端;
(4)Nginx:性能非常好的反向代理服务器,用来做负载均衡,可以在Linux系统中运行。
2、服务器硬件连接
(1)电源(服务器连到电源插座)
(2)网线(服务器连接外网,可以通过ip访问)
(3)主机(服务器通过COM连接自己的主机,可以直接访问)
3、Xshell新建
(1)新建串行接口COM3:文件-新建-名称(N):COM3,协议(P):SERIAL
(2)新建远程接口NUMB:文件-新建-名称(N):192.168.10.156,协议(P):SSH,主机(H):192.168.10.156

十四、VIM编辑器
1、修改或添加
(1)进入文件,命令为:vim /usr/local/con.cfg
(2)按I和上下左右方向键
2、保存并退出
(1)ESC---冒号--wq--enter
(2)ESC---冒号--x--enter
(3)ESC---shift+zz,或ZZ
3、正常退出
(1)无修改退出:ESC---冒号--q
(2)不保存退出:ESC---冒号--q!
(3)强制退出:ESC---冒号--!

十五、Linux常见命令
1、Shell:是系统的用户界面,提供了用户和内核进行交互操作的一种接口。
2、Linux目录结构
(1)bin 存放二进制可执行文件(ls,cat,mkdir等)
(2)boot 存放用于系统引导时使用的各种文件
(3)dev 用于存放设备文件
(4)etc 存放系统配置文件
(5)home 存放所有用户文件的根目录
(6)lib 存放跟文件系统中的程序运行所需要的共享库及内核模块
(7)mnt 系统管理员安装临时文件系统的安装点
(8)opt 额外安装的可选应用程序包所放置的位置
(9)proc 虚拟文件系统,存放当前内存的映射
(10)root 超级用户目录
(11)sbin 存放二进制可执行文件,只有root才能访问
(12)tmp 用于存放各种临时文件
(13)usr 用于存放系统应用程序,比较重要的目录/usr/local 本地管理员软件安装目录
(14)var 用于存放运行时需要改变数据的文件
3、常用指令介绍
(1)文件目录操作命令。ls 显示文件和目录列表;-l 列出文件的详细信息;-a 列出当前目录所有文件,包含隐藏文件
(2)mkdir 创建目录。-p 父目录不存在情况下先生成父目录
(3)cd 切换目录
(4)touch 生成一个空文件
(5)echo 生成一个带内容文件
(6)cat、tac 显示文本文件内容//////////////////////7)cp 复制文件或目录
(8)rm 删除文件。-r 同时删除该目录下的所有文件;-f 强制删除文件或目录
(9)mv 移动文件或目录、文件或
(10)mv aaa bbb 将aaa改名为bbb
(11)find 在文件系统中查找指定的文件。-name 文件名
(12)wc 统计文本文档的行数,字数,字符数
(13)grep 在指定的文本文件中查找指定的字符串
(14)rmdir 删除空目录
(15)tree 显示目录目录改名树 
(16)pwd 显示当前工作目录 
(17)ln 建立链接文件
(18)more、less 分页显示文本文件内容
(19)head、tail分别显示文件开头和结尾内容 
4、系统管理命令
(1)stat 显示指定文件的相关信息,比ls命令显示内容更多 
(2)who、w 显示在线登录用户 
(3)whoami 显示用户自己的身份 
(4)hostname 显示主机名称 
(5)uname显示系统信息 
(6)top 显示当前系统中耗费资源最多的进程 
(7)ps 显示当前处于运行状态的进程(Process Status的简写)
(7-1)a 显示现行终端机下的所有进程,包括其他用户的进程
(7-2)u 以用户为主的格式来显示进程状况
(7-3)x 显示所有进程,不以终端机来区分
(7-4)g 显示现行终端机下的所有进程,包括群组领导者的进程
(7-5)r 只列出现行终端机正在执行中的进程
(7-6)e 列出进程时,显示每个进程所使用的环境变量
(7-7)p 进程识别码
(8)du 显示指定的文件(目录)已使用的磁盘空间的总量 
(9)df 显示文件系统磁盘空间的使用情况 
(10)free 显示当前内存和交换空间的使用情况 
(11)ifconfig 显示网络接口信息(显示或设置网络设备) 
(12)ping 测试网络的连通性 
(13)netstat 显示网络状态信息 
(14)man 命令帮助信息查询
(15)alias 设置命令别名
(16)alias [别名]=[“指令名”]
(17)clear 清屏
(18)kill 杀死进程
5、“|”和“||”
(1)“|”管道符。上一条命令的输出,作为下一条命令参数
(2)“||”逻辑或
6、压缩与解压
(1)zip:zip file.zip file(压缩)和 unzip file.zip(解压)
(2)gzip:gzip file(压缩)和gunzip file.gz(解压)
(3)bzip2:bzip2 file(压缩)和 bunzip2 file.bz2(解压)
(4)tar:tar -cf file.tar file(压缩)和 tar -xf file.tar(解压)
7、关机/重启命令 
(1)shutdown系统关机。r 关机后立即重启;h 关机后不重新启动;now 立即关机;halt 关机后关闭电源;reboot 重新启动
8、“rm -rf”释义 
(1rm:remove;移除
(2r:recursion;[rɪˈkɜːʃn];递归
(3f:force;强制
 
十六、electron
1、electron是什么?
(1)用Web技术构建跨平台的桌面应用,electron = Chromium + Node.js + Native API。20165 月 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类的工具。
 
十七、服务端渲染:每次普通请求,都在服务器里,把动态数据拼接到html字符串里,发送到浏览器渲染。

十八、客户端渲染:每次AJAX请求,服务器只返回json数据,浏览器把数据拼接到首次请求到的html字符串里渲染。
 
十九、__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