国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Webpack 愛與恨

HmyBmny / 3510人閱讀

摘要:關于標題,為什么是愛與恨因為在剛出來的時候,我并不是堅定的支持者,有很多地方用起來不方便,設計不合理。用戶只有首次訪問需要下載全部靜態資源,以后的訪問都直接使用緩存資源。首先,在中添加字段,當為時,則開啟服務。例如請求的是則返回中的數據。

關于標題,為什么是“愛與恨”?

因為在 webpack 剛出來的時候,我并不是堅定的支持者,有很多地方用起來不方便,api 設計不合理。隨著 webpack 和 react 生態的越發完善,加上 webpack2.0 的發布,它的功能也越來越強大,讓我又重新認識它。

內容提要 webpack 構建方案

webpack 生態

需求是什么

對比其他方案

webpack vs gulp

webpack

gulp

什么時候用

webpack 構建方案 webpack 生態

網上有好多介紹 webpack 的文章,本文只簡單介紹兩個基本概念。

Loaders

Plugins

Loaders

webpack 可以使用 loader 來處理文件,允許你打包除 JavaScript 之外的任何靜態資源。

文件

raw-loader 加載文件原始內容

file-loader 將文件發送到輸出文件夾,并返回 URL

url-loader 像 file loader 一樣工作,但如果文件小于限制,可以返回 data URL

編譯

babel-loader 加載 ES2015+ 代碼,然后使用 Babel 轉譯為 ES5

traceur-loader 加載 ES2015+ 代碼,然后使用 Traceur 轉譯為 ES5

ts-loader 像 JavaScript 一樣加載 TypeScript 2.0+

coffee-loader 像 JavaScript 一樣加載 CoffeeScript

模板

html-loader 導出 HTML 為字符串,需要引用靜態資源

markdown-loader 將 Markdown 轉譯為 HTML

handlebars-loader 將 Handlebars 轉譯為 HTML

樣式

css-loader 解析 CSS 文件后,使用 import 加載,并且返回 CSS 代碼

less-loader 加載和轉譯 LESS 文件

sass-loader 加載和轉譯 SASS/SCSS 文件

postcss-loader 使用 PostCSS 加載和轉譯 CSS/SSS 文件

Plugins

CommonsChunkPlugin

將多個入口起點之間共享的公共模塊,生成為一些 chunk,并且分離到多帶帶的 bundle 中,例如,vendor.bundle.js 和 app.bundle.js

DefinePlugin, EnvironmentPlugin

允許在編譯時(compile time)配置的全局常量,用于允許「開發/發布」構建之間的不同行為

ExtractTextWebpackPlugin

從 bundle 中提取 CSS 文本到獨立的文件

HtmlWebpackPlugin

用于簡化 HTML 文件(index.html)的創建,提供訪問 bundle 的服務。

I18nWebpackPlugin

為 bundle 增加國際化支持

NamedModulesPlugin

保留編譯結果的模塊名,便于調試

需求是什么

技術問題還是要從需求出發,我們團隊的實際需求是什么。

區分兩套環境

多頁面多入口

mock 接口數據

iconfont 字體打包

1. 區分兩套環境

develop

production

/build 文件夾編譯結果如下:

/build

  - /develop
    - /pageA
      - index.js
      - index.css
      - index.html
    - /pageB
    - common.js
    - common.css

  - /production
    - /1.0.0
      - /pageA
        - index.js
        - index.css
        - index.html
      - /pageB
      - common.js
      - common.css
    - /1.0.1
      - /pageA
        - index.js
        - index.css
        - index.html
      - /pageB
      - common.js
      - common.css

其中開發環境的 html 編譯結果為:



    
        
        
        首頁
        
        
    
    
        

其中生產環境的 html 編譯結果為:



    
        
        
        首頁
        
        
    
    
        

生產環境的最終頁面上靜態資源路徑是

業界還有一種做法是使用 /path/file.{hash}.js 形式的路徑,都是為了配合 http 緩存策略,做到前端資源的緩存和無縫發布。

緩存策略:在 http 響應頭中,設置 Cache-Control、 ExpiresLast-Modified 控制靜態資源緩存。用戶只有首次訪問需要下載全部靜態資源,以后的訪問都直接使用緩存資源。

cache-control:max-age=31536000
expires:Fri, 06 Apr 2018 08:32:17 GMT
last-modified:Thu, 06 Apr 2017 06:54:04 GMT

對用戶和客戶端來說,每次發布更新代碼,只需要下載新的資源,而無需清除緩存

無縫發布:在團隊合作開發中,往往會遇到新老版本兼容和發布順序的問題。例如原來的 a.js 添加了新功能變成了 a".js,為了避免前端先發布上線的代碼影響線上業務,保證發布上去的代碼兼容舊版本,需要在代碼中添加如下的兼容語句:

if(newVersion) {
  // new feature
} else {
  // old feature
}

而使用增量發布的方式不需要這樣的額外處理,由于每次都是生成新的 url,那么只要后端引用的路徑沒有變化,就始終引用舊資源,一旦后端發布完成就自動引用新資源。

多頁面多入口

雖然 React 天然是開發 SPA 的利器,它的生態中的配套工具也是以解決 SPA 問題為主,例如 React-Redux, React-Saga 等,但是我們的項目中頁面非常簡單,沒有太多的用戶交互,沒有太多的組件間的消息傳遞,如果強行引入這些概念,反而把整個項目搞得非常復雜,因此選用多頁面多入口的方案。使用前面提到的 HtmlWebpackPlugin 插件進行多頁面的構建。

// 編譯 html,多頁面多入口
Object.keys(webpackConfig.entry).forEach(name => {
  webpackConfig.plugins.push(new HtmlWebpackPlugin({
    template: `./src/template.ejs`,
    filename: `${name}.html`,
    chunks: ["common", name]
  }));
});
mock 接口數據

webpack-dev-server 提供了 proxy 代理解決方案,但是沒有解決 mock 接口數據的問題。我們利用 Koa 開發了一個簡版的 mock 服務器,可以加載本地文件中的模擬測試數據。

首先,在 package.json 中添加 mockEnable 字段,當 mockEnable 為 true 時,則開啟 mock 服務。

// package.json
{
  "mockEnable": true,
  "proxy": {
    "/api/**": {
      "target": "http://example.com"
    }
  },
}

其次,在 webpack.config.js 中,將 package.proxy 的 target 指向 mock 服務器

// webpack.config.js
const pkg = require("./package.json");
const MockServer = require("./mock/server.js");

// 將 http://example.com/api/path 的接口,轉發到 http://localhost:8088/api/path
if(pkg.mockEnable) {
  let port = 8088;
  MockServer.start(port);

  Object.keys(pkg.proxy).forEach(filter => {
    let proxy = pkg.proxy[filter];
    proxy.target = `http://localhost:${port}`; // mock server
  });
}

最后,在 mock 服務器中處理請求,mock server 的邏輯很簡單,只有不到 50 行代碼:

// mock/server.js
const fs = require("fs");
const path = require("path");
const color = require("colorful");

const Koa = require("koa");
const router = require("koa-router")();

let app = new Koa();

/* 訪問日志,logger */
app.use(async function (ctx, next) {
  console.log(color.green("Mock Server"), (new Date()).toLocaleString(), "url:", ctx.url);
  await next();
});

/* 路由,router */
router.all("*", async (ctx) => {
  let filepath = path.resolve(__dirname, "data", `./${ctx.url}.json`);
  let methodFilepath = path.resolve(__dirname, "data", `./${ctx.url}.${ctx.method}.json`);
  if(fs.existsSync(filepath)) {
    ctx.body = require(filepath);
  } else if(fs.existsSync(methodFilepath)) {
    ctx.body = require(methodFilepath);
  } else {
    ctx.status = 404;
    ctx.body = "Mock data not found";
  }
}); 
app.use(router.routes()).use(router.allowedMethods());

/* 啟動 Mock Server */
exports.start = function(port) {
  app.listen(port, () => {
    console.log("Mock Server started on", color.green(`http://127.0.0.1:${port}/`));
  });
  return app;
}

最終的效果是,只要開啟了 mockEnable,當用戶在頁面上發起請求時,自動返回本地文件中的模擬數據。例如請求的是GET http://localhost/api/path/users則返回/mock/data/api/path/users.json
中的數據。如果同一個 url 既有 GET 請求又有 POST 請求,則可以通過如下方式避免沖突

/mock/data/api/path/users.get.json
/mock/data/api/path/users.post.json
iconfont 字體打包

我們的項目是基于 Ant Design 做二次開發,由于 ant design 的 iconfont 會依賴 https://at.alicdn.com/ 的字體資源,而公司內網不能訪問外部資源,所以需要將字體打包到自己的應用里。利用 less-loader 的 modifyVars 屬性,修改 antd 里的 @icon-url 變量。

先設置 @icon-url 的變量值。

// webpack.config.js
let cssVars = {
  "@icon-url": ""/assets/iconfont/iconfont"",
}

然后在 less-loader 的參數中設置 modifyVars。

// webpack.config.js
{
  test: /.less$/,
  use: ExtractTextPlugin.extract([
    "css-loader", 
    { loader:"less-loader", options: { modifyVars:cssVars } }
  ])
}
對比其他方案

atool-build

預設了適用于 antd 的 webpack 構建腳本

配置非常靈活,幾乎支持所有場景的定制

對插件的修改略麻煩

版本升級兼容性不太好

roadhog

使用非常簡單,不用關心那么多概念

自定義的靈活性受局限

Webpack vs Gulp

先看看 webpack 和 gulp 各自的官方說明:

Webpack

webpack is a module bundler for modern JavaScript applications.

Gulp

gulp is a toolkit for automating painful or time-consuming tasks in your development workflow, so you can stop messing around and build something.

從上述官方描述可以看出,webpack 的核心概念是 module bundler,而 gulp 的核心概念是 toolkit for tasks。一個側重模塊打包,一個側重自動化任務處理。

webpack - 一切皆是模塊

從官方網站上的圖片可以看出,一切皆是模塊,不管是 js 模塊,還是 css、sass 樣式,還是模板(hds)、圖片(jpg/png)、字體等資源,都以被 webpack 當做互相依賴的模塊(modules with dependencies)處理。經過 loader 的解析,最終處理成頁面上可用的靜態資源(static assets)。由于模塊間需要有互相依賴關系,因此需要在 js 里 require 樣式和圖片等資源。

蛋疼的 api,webpack loader 的參數形式簡直反人類,這種字符串拼接的方式不直觀且不方便擴展

require("file-loader?name=js/[hash].script.[ext]!./javascript.js");

require("file-loader?name=html-[hash:6].html!./page.html");

require("file-loader?name=[hash]!./flash.txt");

require("file-loader?name=[sha512:hash:base64:7].[ext]!./image.png");

require("file-loader?name=img-[sha512:hash:base64:7].[ext]!./image.jpg");

require("file-loader?name=picture.png!./myself.png");

require("file-loader?name=[path][name].[ext]?[hash]!./dir/file.png")

以下是一個簡單的 webpack 的例子:

// webpack.config.js
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

let webpackConfig = {
  entry: {
    index: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, "./build"),
    filename: "[name].js",
    publicPath: "./"
  },
  module: {
    rules: [{
      test: /.jsx?$/,
      exclude: /node_modules/,
      use: {
        loader: "babel-loader"
      }
    }, {
      test: /.less$/,
      use: ExtractTextPlugin.extract([
        "css-loader", 
        "less-loader"
      ])
    }, {
      test: /.(png|jpg|jpeg|gif)$/i,
      use: { 
        loader:"file-loader", 
        options: {
          name: "static/images/[name].[ext]"
        }
      }
    }, {
      test: /.(woff2?|ttf|eot|svg)$/,
      use: { 
        loader:"file-loader", 
        options: {
          name: "static/fonts/[name].[ext]"
        }
      }
    }]
  },
  plugins: [
    new ExtractTextPlugin("[name].css"),
    new UglifyJSPlugin(),
    new CleanWebpackPlugin(["./build"]),
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html",
      chunks: ["index"],
      title: "首頁",
      message: "webpack 測試頁面"
    })
  ]
};

module.exports = webpackConfig;
gulp - 一切基于任務

gulp 是作為一個 task runner 存在的,最核心的功能是自動化任務執行,復雜任務組織,基于文件 stream 的構建,加上完善的插件體系,處理各種類型的任務執行流程。用戶可以預先定義好一系列的 task,定義好這些 task 分別做些什么,然后定義好執行順序,最后由 gulp 來執行這些 task。所以 gulp 可以做到幾乎所有 node 能做到的事情,不僅僅是用來打包 js。

下面是一個簡單的 gulp 的例子:

// gulpfile.js
const gulp = require("gulp");
const clean = require("del");
const ejs = require("gulp-ejs");
const less = require("gulp-less");
const jsmin  = require("gulp-jsmin");
const minifyCSS = require("gulp-csso");

gulp.task("html", function(){
  return gulp.src("src/*.html")
    .pipe(ejs({
      title: "首頁",
      message: "gulp 測試頁面"
    }))
    .pipe(gulp.dest("build"))
});

gulp.task("css", function(){
  return gulp.src("src/*.less")
    .pipe(less())
    .pipe(minifyCSS())
    .pipe(gulp.dest("build"))
});

gulp.task("js", function () {
    gulp.src(["src/*.js"])
        .pipe(jsmin())
        .pipe(gulp.dest("build"))
});

gulp.task("clean", function () {
    clean(["build"]);
});

gulp.task("clone", function () {
    gulp.src(["static/**"])
        .pipe(gulp.dest("build/static/"))
});

gulp.task("default", ["clean", "clone", "html", "css", "js" ]);
webpack vs gulp

下面對比 webpack 和 gulp 各自適合的場景

webpack

基于模塊依賴的打包構建

模塊切割

公共模塊提取

gulp

與模塊化無關的構建過程

js / css 批量壓縮

圖片壓縮

批量文本替換

復雜的任務處理

項目發布任務

啟動服務器

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83162.html

相關文章

  • 從實踐到原理,帶你參透 gRPC

    摘要:原文地址從實踐到原理,帶你參透在語言中大放異彩,越來越多的小伙伴在使用,最近也在公司安利了一波,希望能通過這篇文章能帶你一覽的愛與恨。幀的主要作用是裝填主體信息,是數據幀。 showImg(https://segmentfault.com/img/remote/1460000019552245); 原文地址:從實踐到原理,帶你參透 gRPC gRPC 在 Go 語言中大放異彩,越來越多...

    geekidentity 評論0 收藏0
  • 【回顧九月份第二周】 前端你該知道的事兒

    摘要:順便一說,這首歌的原唱是秋田,中島當年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執導,金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...

    sixgo 評論0 收藏0
  • 【回顧九月份第二周】 前端你該知道的事兒

    摘要:順便一說,這首歌的原唱是秋田,中島當年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執導,金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...

    levius 評論0 收藏0
  • B站運維團隊成長的血淚史

    摘要:胡凱,運維負責人,曾經就職于金山軟件金山網絡獵豹移動,負責運維相關工作。胡凱在去年加入站剛剛成立的運維部,人少事多,遇到了很多坑。 胡凱,bilibili運維負責人,曾經就職于金山軟件、金山網絡、獵豹移動,負責運維相關工作。Bilibili是國內最大的年輕人潮流文化娛樂社區,銀河系知名彈幕視頻分享UGC平臺。 95后二次元新人類的追捧,讓以視頻彈幕、UP主聞名于世的bilibili(...

    gitmilk 評論0 收藏0

發表評論

0條評論

HmyBmny

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<