zoukankan      html  css  js  c++  java
  • 【webpack】-- 自动刷新与解析

    前端需要频繁的修改js和样式,且需要根据浏览器的页面效果不断的做调整;而且往往我们的开发目录和本地发布目录不是同一个,修改之后需要发布一下;另外一点就是并不是所有的效果都可以直接双击页面就能看到,我们常常需要在本地用nginx建一个站点来观察(自己电脑上ok了才放到测试环境去)。所以如果要用手工刷新浏览器和手动(或点击)发布,还要启动站点,确实是个不小的体力活。而这三点webpack可以帮我们做到。

    webpack-dev-server

    webpack是通过webpack-dev-server(WDS)来实现自动刷新。WDS是一个运行在内存中的开发服务器(一个express)。启动之后,它会检测文件是否发生改变并再自动编译一次。

    1.安装

    npm install webpack-dev-server --save-dev

    先通过npm将其安装到开发目录。安装完成之后会在node_modules/bin下找到。

    2.npm启动

    然后修改package.json:(基于上一节)

     "scripts": {
        "start": "webpack-dev-server --env development",
        "build": "webpack --env production"
      }

    现在就可以通过npm run start 或者 npm start来启动了。

    启动之后,可以看到Project is running at http://localhost:8080 上面。打开页面

    说明WDS已经帮我们自动建了一个站点.我们修改component.js ,cmd中会出现编译,页面会自动刷新。

    3.直接启动

    官网介绍可以直接通过下面的命令启动WDS。

    webpack-dev-server --env development

    但会出现webpack-dev-server --env development 不是内部命令的提示,这种问题都是环境变量的问题,将你开发的bin目录设置到环境变量中即可,比如我的目录是‘E:Html5 ode_modules.bin’,就加上分号写在后面。

    C:UsersAdministrator.9BBOFZPACSCXLG2AppDataRoaming
    pm;C:Program Files (x86)Microsoft VS Codein;E:Html5
    ode_modules.bin

    4.8080端口占用

    如果默认的8080端口占用,WDS会换一个。比如用nginx先发布一个。

       server{
          listen       8080;
          location / {
               root   E:/Html5/build;
               index  index.html index.htm;
            }
        }

    再启动WDS:

    端口切到了8081。也可以手动配置端口:

     devServer:{
       //...
        port: 9000
    }

    nodemon 自动启动

     WDS是监视开发文件的,webpack.config.js改变不会引起自动启动。所以我们需要nodemon去做这件事情。

    npm install nodemon --save-dev

    先安装在开发目录,然后修改package.json:

     "scripts": {
       "start": "nodemon --watch webpack.config.js --exec "webpack-dev-server --env development"",
        "build": "webpack --env production"
      },

    等于让nodemon去监视webpack.config.js,变化了就去启动它。

    这样就你可以让你的双手专心的开发了。

    代理

    不过有一点疑问,就是WDS这个站点的替代性,因为我们自己部署的nginx有一些api的代理。如果挂在WDS的这个默认站点上自然是无法访问的。换句话说可否给WDS配置一个刷新路径。如果文件改变去刷新指定的地址,或者让我去配个代理。既然它本身是一个http服务器,肯定也有代理的功能。搜了下果然有:https://github.com/webpack/webpack-dev-server/tree/master/examples/proxy-advanced

    module.exports = {
        context: __dirname,
        entry: "./app.js",
        devServer: {
            proxy: {
                "/api": {
                    target: "http://jsonplaceholder.typicode.com/",
                    changeOrigin: true,
                    pathRewrite: {
                        "^/api": ""
                    },
                    bypass: function(req) {
                        if(req.url === "/api/nope") {
                            return "/bypass.html";
                        }
                    }
                }
            }
        }
    }

    即将api这个字段替换成http://jsonplaceholder.typicode.com/,并将其从原地址中删掉,这样就可以自己实现代理了。皆大欢喜!WDS是通过 http-proxy-middleware 来实现代理。更多参考:http://webpack.github.io/docs/webpack-dev-server.html#bypass-the-proxy;https://github.com/chimurai/http-proxy-middleware#options

    but,这种刷新是怎么实现的呢?因为页面上没有嵌入什么别的js,去翻原码 web-dev-server/server.js中有这么一段:

    Server.prototype._watch = function(path) {
        const watcher = chokidar.watch(path).on("change", function() {
            this.sockWrite(this.sockets, "content-changed");
        }.bind(this))
    
        this.contentBaseWatchers.push(watcher);
    }

    chokidar来监视文件变化,server的内部维护的有一个socket集合:

    Server.prototype.sockWrite = function(sockets, type, data) {
        sockets.forEach(function(sock) {
            sock.write(JSON.stringify({
                type: type,
                data: data
            }));
        });
    }

    sock是一个sockjs对象。https://github.com/sockjs/sockjs-client,从http://localhost:8080/webpack-dev-server/页面来看,sockjs是用来通信记录日志的。  

    var onSocketMsg = {
        hot: function() {
            hot = true;
            log("info", "[WDS] Hot Module Replacement enabled.");
        },
        invalid: function() {
            log("info", "[WDS] App updated. Recompiling...");
            sendMsg("Invalid");
        },
        hash: function(hash) {
            currentHash = hash;
        },
    ...
    }

    我们在看app.js,其中有一个OnSocketMsg 对象。

    var onSocketMsg = {
        hot: function() {
            hot = true;
            log("info", "[WDS] Hot Module Replacement enabled.");
        },
        invalid: function() {
            log("info", "[WDS] App updated. Recompiling...");
            sendMsg("Invalid");
        },
        hash: function(hash) {
            currentHash = hash;
        },
        "still-ok": function() {
            log("info", "[WDS] Nothing changed.")
            if(useWarningOverlay || useErrorOverlay) overlay.clear();
            sendMsg("StillOk");
        },
        "log-level": function(level) {
            logLevel = level;
        },
        "overlay": function(overlay) {
            if(typeof document !== "undefined") {
                if(typeof(overlay) === "boolean") {
                    useWarningOverlay = overlay;
                    useErrorOverlay = overlay;
                } else if(overlay) {
                    useWarningOverlay = overlay.warnings;
                    useErrorOverlay = overlay.errors;
                }
            }
        },
        ok: function() {
            sendMsg("Ok");
            if(useWarningOverlay || useErrorOverlay) overlay.clear();
            if(initial) return initial = false;
            reloadApp();
        },
        "content-changed": function() {
            log("info", "[WDS] Content base changed. Reloading...")
            self.location.reload();
        },
        warnings: function(warnings) {
            log("info", "[WDS] Warnings while compiling.");
            var strippedWarnings = warnings.map(function(warning) {
                return stripAnsi(warning);
            });
            sendMsg("Warnings", strippedWarnings);
            for(var i = 0; i < strippedWarnings.length; i++)
                console.warn(strippedWarnings[i]);
            if(useWarningOverlay) overlay.showMessage(warnings);
    
            if(initial) return initial = false;
            reloadApp();
        },
        errors: function(errors) {
            log("info", "[WDS] Errors while compiling. Reload prevented.");
            var strippedErrors = errors.map(function(error) {
                return stripAnsi(error);
            });
            sendMsg("Errors", strippedErrors);
            for(var i = 0; i < strippedErrors.length; i++)
                console.error(strippedErrors[i]);
            if(useErrorOverlay) overlay.showMessage(errors);
        },
        close: function() {
            log("error", "[WDS] Disconnected!");
            sendMsg("Close");
        }
    };
    View Code

    ok的时候触发一个reloadApp

    function reloadApp() {
        if(hot) {
            log("info", "[WDS] App hot update...");
            var hotEmitter = __webpack_require__("./node_modules/webpack/hot/emitter.js");
            hotEmitter.emit("webpackHotUpdate", currentHash);
            if(typeof self !== "undefined") {
                // broadcast update to window
                self.postMessage("webpackHotUpdate" + currentHash, "*");
            }
        } else {
            log("info", "[WDS] App updated. Reloading...");
            self.location.reload();
        }
    }

    也就是说WDS先检测文件是否变化,然后通过sockjs通知到客户端,这样就实现了刷新。之前WebSocket的第三方只用过socket.io,看起来sockjs也蛮好用的。不必外带一个js,在主js里面就可以写了。

    小结:效率提高的一方面是将一些机械的重复性流程或动作自动化起来。WDS和nodemon就是两个为你干活的小弟。 

    demo:http://files.cnblogs.com/files/stoneniqiu/webpack-ch2.zip

  • 相关阅读:
    爬虫 爬取糗事百科热门板块的信息
    爬虫 爬取豆瓣高分电影信息
    django model之Meta选项
    ubuntu下无法获得锁 /var/lib/apt/lists/lock – open (11: 资源暂时不可用)
    django 通过数据库表名获取app名
    JS自定义字符串格式化函数
    django 制作上传图片并预览的效果
    Django序列化
    Django以ajax方式提交form
    Manjaro20 Linux安装VS Code
  • 原文地址:https://www.cnblogs.com/stoneniqiu/p/6444960.html
Copyright © 2011-2022 走看看