成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Webpack 愛與恨

HmyBmny / 3524人閱讀

摘要:關(guān)于標(biāo)題,為什么是愛與恨因?yàn)樵趧偝鰜淼臅r(shí)候,我并不是堅(jiān)定的支持者,有很多地方用起來不方便,設(shè)計(jì)不合理。用戶只有首次訪問需要下載全部靜態(tài)資源,以后的訪問都直接使用緩存資源。首先,在中添加字段,當(dāng)為時(shí),則開啟服務(wù)。例如請(qǐng)求的是則返回中的數(shù)據(jù)。

關(guān)于標(biāo)題,為什么是“愛與恨”?

因?yàn)樵?webpack 剛出來的時(shí)候,我并不是堅(jiān)定的支持者,有很多地方用起來不方便,api 設(shè)計(jì)不合理。隨著 webpack 和 react 生態(tài)的越發(fā)完善,加上 webpack2.0 的發(fā)布,它的功能也越來越強(qiáng)大,讓我又重新認(rèn)識(shí)它。

內(nèi)容提要 webpack 構(gòu)建方案

webpack 生態(tài)

需求是什么

對(duì)比其他方案

webpack vs gulp

webpack

gulp

什么時(shí)候用

webpack 構(gòu)建方案 webpack 生態(tài)

網(wǎng)上有好多介紹 webpack 的文章,本文只簡單介紹兩個(gè)基本概念。

Loaders

Plugins

Loaders

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

文件

raw-loader 加載文件原始內(nèi)容

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

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

編譯

babel-loader 加載 ES2015+ 代碼,然后使用 Babel 轉(zhuǎn)譯為 ES5

traceur-loader 加載 ES2015+ 代碼,然后使用 Traceur 轉(zhuǎn)譯為 ES5

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

coffee-loader 像 JavaScript 一樣加載 CoffeeScript

模板

html-loader 導(dǎo)出 HTML 為字符串,需要引用靜態(tài)資源

markdown-loader 將 Markdown 轉(zhuǎn)譯為 HTML

handlebars-loader 將 Handlebars 轉(zhuǎn)譯為 HTML

樣式

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

less-loader 加載和轉(zhuǎn)譯 LESS 文件

sass-loader 加載和轉(zhuǎn)譯 SASS/SCSS 文件

postcss-loader 使用 PostCSS 加載和轉(zhuǎn)譯 CSS/SSS 文件

Plugins

CommonsChunkPlugin

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

DefinePlugin, EnvironmentPlugin

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

ExtractTextWebpackPlugin

從 bundle 中提取 CSS 文本到獨(dú)立的文件

HtmlWebpackPlugin

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

I18nWebpackPlugin

為 bundle 增加國際化支持

NamedModulesPlugin

保留編譯結(jié)果的模塊名,便于調(diào)試

需求是什么

技術(shù)問題還是要從需求出發(fā),我們團(tuán)隊(duì)的實(shí)際需求是什么。

區(qū)分兩套環(huán)境

多頁面多入口

mock 接口數(shù)據(jù)

iconfont 字體打包

1. 區(qū)分兩套環(huán)境

develop

production

/build 文件夾編譯結(jié)果如下:

/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

其中開發(fā)環(huán)境的 html 編譯結(jié)果為:



    
        
        
        首頁
        
        
    
    
        

其中生產(chǎn)環(huán)境的 html 編譯結(jié)果為:



    
        
        
        首頁
        
        
    
    
        

生產(chǎn)環(huán)境的最終頁面上靜態(tài)資源路徑是

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

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

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

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

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

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

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

多頁面多入口

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

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

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

首先,在 package.json 中添加 mockEnable 字段,當(dāng) mockEnable 為 true 時(shí),則開啟 mock 服務(wù)。

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

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

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

// 將 http://example.com/api/path 的接口,轉(zhuǎn)發(fā)到 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 服務(wù)器中處理請(qǐng)求,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());

/* 啟動(dòng) 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,當(dāng)用戶在頁面上發(fā)起請(qǐng)求時(shí),自動(dòng)返回本地文件中的模擬數(shù)據(jù)。例如請(qǐng)求的是GET http://localhost/api/path/users則返回/mock/data/api/path/users.json
中的數(shù)據(jù)。如果同一個(gè) url 既有 GET 請(qǐng)求又有 POST 請(qǐng)求,則可以通過如下方式避免沖突

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

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

先設(shè)置 @icon-url 的變量值。

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

然后在 less-loader 的參數(shù)中設(shè)置 modifyVars。

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

atool-build

預(yù)設(shè)了適用于 antd 的 webpack 構(gòu)建腳本

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

對(duì)插件的修改略麻煩

版本升級(jí)兼容性不太好

roadhog

使用非常簡單,不用關(guān)心那么多概念

自定義的靈活性受局限

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。一個(gè)側(cè)重模塊打包,一個(gè)側(cè)重自動(dòng)化任務(wù)處理。

webpack - 一切皆是模塊

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

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

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")

以下是一個(gè)簡單的 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 - 一切基于任務(wù)

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

下面是一個(gè)簡單的 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

下面對(duì)比 webpack 和 gulp 各自適合的場景

webpack

基于模塊依賴的打包構(gòu)建

模塊切割

公共模塊提取

gulp

與模塊化無關(guān)的構(gòu)建過程

js / css 批量壓縮

圖片壓縮

批量文本替換

復(fù)雜的任務(wù)處理

項(xiàng)目發(fā)布任務(wù)

啟動(dòng)服務(wù)器

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83162.html

相關(guān)文章

  • 從實(shí)踐到原理,帶你參透 gRPC

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

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

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

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

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

    levius 評(píng)論0 收藏0
  • B站運(yùn)維團(tuán)隊(duì)成長的血淚史

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

    gitmilk 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<