webpack實踐最后一篇

AAIOpen 8年前發布 | 16K 次閱讀 Node.js 前端技術 webpack

 

溫故而知新

這應該是目前這個階段最后一篇關于webpack的實踐經驗,也許你會學習到該用怎樣的思想去使用webpack,也許你會認為這是一坨屎一樣的文字。不過,我會盡量的描述,我們的實踐以及給出一份在Mac和Win下的Demo,這個項目也是我們應用在PC端的實踐,訪問 https://github.com/sapling-team/generator-sapling-pc 來閱讀我們PC端的腳手架吧。(完美兼容IE8+)

我們對 backbone 也提供了一份有用的擴展,可訪問: https://github.com/sapling-team/base-extend-backbone

更多基礎的配置信息,建議大家閱讀 《webpack在PC項目中的應用》

該用什么樣的思想來使用

你用的始終還是Node.js環境

我覺得你應該要忘記webpack,因為你使用的終歸還是Node.js。為什么這么說,因為如果只使用簡單的配置,你可能只把它做為一個模塊加載器。如果你熟練的使用了Node.Js那么恭喜你,我們將用環境的思維來使用它,并用Node.Js來驅動你的構建流程。(NPM可以使用的模塊,你都可以在構建環境中使用)

首先,我們應該將腳本文件放置在bin目錄下,這是unix編程的常識。接著,對于你的產品,定義兩個環境:dev和product,在NPM Scripts中使用 NODE_ENV=dev webpack --config bin/webpack.config ,然后在腳本文件中使用 process.env.NODE_ENV 來獲取環境變量并區分執行。(很不幸的是,Win用戶無法獲取ENV,所以你需要建立兩個文件來做dev和product)

抽象dir

抽象你的目錄資源,設計一定的規則,可以進行批處理配置信息。

npm install glob --save-dev --verbose

我們的入口文件都放置在src中,根據業務特點來命名,比如: index.js , code.js 。

var path = require('path');
var glob = require('glob');

module.exports = getEntry;

function getEntry(sourcePath){
    var entrys = {};
    var basename;
    glob.sync(sourcePath).forEach(function(entry){
        basename = path.basename(entry,path.extname(entry));
        entrys[basename] = entry;
    });
    return entrys;
}

在 webpack.dev.config.js 文件,可以通過getEntry函數來統一處理入口,并得到 entry 配置對象。如果你是多頁面多入口的項目,建議你使用統一的命名規則,比如頁面叫 index.html ,那么你的js和css入口文件也應該叫 index.js 和 index.css 。

include

在編譯期來決定最終呈現什么樣的HTML

在后端語言的模板中 include 是一個非常有用的特性,因為它可以抽象分離不同的HTML結構,來達到復用的目的。

npm install jade-loader --save-dev --verbose

doctype html
html(lang="en")
    head
        - var titleValue = htmlWebpackPlugin.options.title
        title=titleValue
        meta(charset="UTF-8")
    body
        include common/header
        include index/container
        include common/footer
        include common/lib
- var src;
- var map = ['jquery/dist/jquery.min.js','underscore/underscore-min.js','backbone/backbone-min.js']
if htmlWebpackPlugin.options.cdn
    - src = 'http://127.0.0.1:3000/www/link/'
else
    - src = '/link/'
each val in map
    script(type="text/javascript",src=src+val)
{
    test:/.jade$/,
    loader:'jade-loader',
    exclude:/(node_modules)/
}

不僅如此 jade 還可以做更高靈活的配置。

html-webpack-plugin

如果你是多頁面,或者單頁應用都需要這個插件來幫忙處理HTML的內容,比如上述的jade模板的 include 。

var pages = getEntry('./app/web/*.jade');
for(var chunkname in pages){
    var conf = {
        cdn:false,
        filename:chunkname+'.html',
        template:pages[chunkname],
        inject:true,
        minify:{
            removeComments:true,
            collapseWhitespace: false
        },
        chunks:['common',chunkname],
        hash:false
    }
    plugins.push(new HtmlWebpackPlugin(conf));
}

根據 抽象dir 的方法,我們可以通過 getEntry 來獲取一個pages對象,并使用chunks來處理每一個入口頁面的依賴。

如果你是單頁應用,你只需要添加一次HtmlWebpackPlugin插件即可。

如何優化

優化,但不要過度的優化

運行 npm run product 來構建你的發布資源。

過度優化的結果:

.title {
  margin-left: auto;
  margin-right: auto;
  .size(margin-top, 15px);
  .size(margin-bottom, 15px);
}

最后經過webpack的優化變成了:

.title {
  margin: 2.6408vh auto 2.6408vh;
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}

那么問題來了Android4.3以下版本是不支持vw,vh單位的。

我認為對于一個項目,優化的方式應該可以從下列的幾個點中去挖掘:

externals 分離

善用 externals 將過大的文件分離出去,然后再用 script 標簽引用即可。

alias機制

給一些模塊啟用別名,來提高webpack的搜索速度。

將某些對象暴露在全局

  • 在loader中使用 expose 將對象暴露出去 loader: 'expose?jQuery'
  • 使用 ProvidePlugin 插件的幫助
new webpack.ProvidePlugin({
    "M": "mock",
}),

假設 mock 對象中有 set , get 方法,那么此刻你可以在使用 M.set , M.get 方式來調用。

啟用熱替換

  • 將代碼內斂到入口js文件中,然后啟動 webpack.HotModuleReplacementPlugin 插件
  • 使用自帶的 webpack-dev-server 啟動一個服務器
  • 直接在 webpack.config.js 文件中配置
//配置

devServer:{
port:4000,
contentBase:'./app',
historyApiFallback:true
}

合理的使用CommonsChunkPlugin將每一個chunk分割開,并提取

CommonsChunkPlugin 有一些屬性,比如 minChunks 可以設置如果 require 幾次再提取的問題。

個別項目環境變量優化

定義你的 process.env.NODE_ENV 變量,啟用 DefinePlugin 插件來優化警告信息,很多框架,比如react都帶有警告,比如:

if(process.env.NODE_ENV !== 'production'){

}

在prodcut期,我們可以通過 DefinePlugin 來打入環境變量來將這些剔除。

plugins.push(new webpack.DefinePlugin({
    'process.env':{
        'NODE_ENV':JSON.stringify(process.env.NODE_ENV)
    }
}));

構建期間 process.env.NODE_ENV !== 'production' 會變成:

if(false){

}

壓縮工具,會忽略false內的內容,你會發現體積將減少了很多。

清理工作

每次 npm run product 之后,因為設置了 hash 屬性,所以會生成不同的文件,那么問題來了,我無法清理www目錄,那么這時候,就可以換到Node.js的文件系統上了。

var fs = require('fs');
var path = require('path');
var containerPath = path.resolve('./');

module.exports = rmdir;

function rmdir(dirPath){
    dirPath = path.resolve(containerPath,dirPath);
    var dirs = [];
    collection(dirPath,dirs);
    dirs.forEach(function(v){
        var status = fs.rmdirSync(v);
        if(status){
            console.log(status);
        }
    });
}

function collection(url,dirs){
    var stat = fs.statSync(url);
    if(stat.isDirectory()){
        dirs.unshift(url);
        recursion(url,dirs);
    }else{
        if(stat.isFile()){
            fs.unlinkSync(url);
        }
    }
}

function recursion(url,dirs){
    var arr = fs.readdirSync(url);
    var i = 0;
    var le = arr.length;
    for(;i<le;i++){
        var v = path.resolve(url,arr[i]);
        collection(v,dirs);
    }
}

運行腳手架Demo

你可以下載腳手架項目跑一跑: https://github.com/sapling-team/generator-sapling-pc

最終的發布可能還是需要gulp的一些輔助,不過這不要緊了,它只是幫助我們挪動了一些文件,最終成為了一個 www 目錄。

來自: http://div.io/topic/1684

 本文由用戶 AAIOpen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!