基於webpack的前端工程化開發之多頁站點篇(一)

前言碎語

在最初接觸webpack的較長一段時間裏,我(也可能不少人)都以爲webpack是專爲單頁應用而量身打造的,好比webpack+react、webpack+vue等,均可以近乎完美的解決各類資源的依賴加載、打包的問題。甚至css都是打包在js裏去動態添加到dom文檔中去。javascript

後來想一想,這麼好的工具這麼好的方案爲何不能用在website(普通的web站點,姑且叫作website吧)中呢?css

  • 首先對於普通的web站點,咱們更傾向於將css獨立出來,由於對於website來講,css仍是要最早加載出來比較好。html

  • 再而後js咱們也只想加載須要的部分,而不是一個大大的打包了全部js模塊的包。前端

在不少webpack入門級的demo裏,不管是單入口的仍是多入口的,都沒有解決上面兩個問題。入門畢竟是入門,要晉級仍是隻能靠本身。幸運的是,有不少優秀的工程師已爲咱們鋪好了路,讓咱們在前端工程化的道路上少走不少的彎路。若是你也同樣曾迷茫過,請不要走開,但願這裏能爲你答疑解惑。vue

好吧,以上統統是廢話,接下來上乾貨。java

首先開始構建咱們的項目目錄結構。node

初始化項目、安裝依賴

使用npm init初始化項目就很少說了,生成package.json文件。react

使用npm install plugins --save-dev安裝項目所需依賴。最終package.json的依賴聲明以下:jquery

"devDependencies": {
    "css-loader": "^0.23.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "html-loader": "^0.4.3",
    "html-webpack-plugin": "^2.9.0",
    "jquery": "^1.12.0",
    "less": "^2.6.0",
    "less-loader": "^2.2.2",
    "style-loader": "^0.13.0",
    "url-loader": "^0.5.7",
    "webpack": "^1.12.13",
    "webpack-dev-server": "^1.14.1"
}

主要目錄結構

- website
    - src                #代碼開發目錄
        - css            #css目錄,按照頁面(模塊)、通用、第三方三個級別進行組織
            + page
            + common
            + lib
        + img            #圖片資源
        - js             #JS腳本,按照page、components進行組織
            + page
            + components
        + view           #HTML模板
    - dist               #webpack編譯打包輸出目錄,無需創建目錄可由webpack根據配置自動生成
        + css                
        + js
        + view
    + node_modules       #所使用的nodejs模塊
    package.json         #項目配置
    webpack.config.js    #webpack配置
    README.md            #項目說明

假如你是一名純粹的前端工程師,使用webpack構建website的目錄結構大概就這樣了,固然你也能夠根據本身的喜愛自由設計目錄結構。webpack

詳細的代碼全貌能夠提早在這裏「窺看」——https://github.com/vhtml/webpack-MultiPage-static

目錄組織好,咱們就能夠開始擼代碼了。

開發頁面

在src/js/page目錄下創建index.js文件,在src/view目錄下創建index.html文件。入口js和模板文件名對應。

index.js內容以下:

//引入css
require("../../css/lib/reset.css");
require("../../css/common/global.css");
require("../../css/common/grid.css");
require("../../css/page/index.less");


$('.g-bd').append('<p class="text">這是由js生成的一句話。</p>');

index.html 內容以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
    <meta name="description" content="基於webpack的前端工程化開發解決方案探索"/>
    <!--
        描述:head中無需再引入css以及facicon,webpack將根據入口JS文件的要求自動實現按需加載或者生成style標籤
    -->
</head>
<body>
    <div class="g-hd"></div>
    <div class="g-bd">
        <input type="button" value="彈窗" class="btn">
        <p class="img">
            <img src="../img/4.png" alt="">
        </p>
    </div>
    <div class="g-ft"></div>
    <!--
        描述:body中一樣無需單獨引入JS文件,webpack會根據入口JS文件自動實現按需加載或者生成script標籤,還能夠生成對應的hash值
    -->
</body>
</html>

就是這樣一個簡單的HTML模板,咱們甚至沒有引入任何CSS和JS,經過webpack打包就能夠自動幫咱們引入。

因爲是作website,在此以前相信你對單頁應用打包已經有過了解,我就不客氣了,再來兩個頁面壓壓驚。

about.js:

//引入css
require("../../css/lib/reset.css");
require("../../css/common/global.css");
require("../../css/common/grid.css");
require("../../css/page/about.less");

$('#about').html('這是一個關於webpack構建工程的栗子');

about.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>關於</title>
    <meta name="description" content="基於webpack的前端工程化開發解決方案探索"/>
</head>
<body>
    <div class="g-hd"></div>
    <div class="g-bd">
        <div id="about"></div>
    </div>
    <div class="g-ft"></div>
</body>
</html>

list.js:

//引入css
require("../../css/lib/reset.css");
require("../../css/common/global.css");
require("../../css/common/grid.css");
require("../../css/page/list.less");


var html = '';
for(var i=0;i<5;i++){
    html += '<li>列表'+(i+1)+'</li>';
}

$('#list').html(html);

list.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表頁</title>
    <meta name="description" content="基於webpack的前端工程化開發解決方案探索"/>
</head>
<body>
    <div class="g-hd"></div>
    <div class="g-bd">
        <ul id="list"></ul>
    </div>
    <div class="g-ft"></div>
</body>
</html>

OK,太棒了!!!

webpack配置及項目打包編譯

這裏是關鍵,在webpack.config.js裏,咱們將進行一些配置,來完成咱們的需求,一開始或許有點難理解,但等你真的掌握了,你便會驚呼它的神奇。配置中我寫了詳細的註釋,要想完全理解,還需多實踐,多查閱文檔,必要時看看源碼,嗚呼,學習之路漫漫兮。

var path = require('path');
var webpack = require('webpack');
/*
extract-text-webpack-plugin插件,
有了它就能夠將你的樣式提取到單獨的css文件裏,
媽媽不再用擔憂樣式會被打包到js文件裏了。
 */
var ExtractTextPlugin = require('extract-text-webpack-plugin');
/*
html-webpack-plugin插件,重中之重,webpack中生成HTML的插件,
具體能夠去這裏查看https://www.npmjs.com/package/html-webpack-plugin
 */
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: { //配置入口文件,有幾個寫幾個
        index: './src/js/page/index.js',
        list: './src/js/page/list.js',
        about: './src/js/page/about.js',
    },
    output: { 
        path: path.join(__dirname, 'dist'), //輸出目錄的配置,模板、樣式、腳本、圖片等資源的路徑配置都相對於它
        publicPath: '/dist/',                //模板、樣式、腳本、圖片等資源對應的server上的路徑
        filename: 'js/[name].js',            //每一個頁面對應的主js的生成配置
        chunkFilename: 'js/[id].chunk.js'   //chunk生成的配置
    },
    module: {
        loaders: [ //加載器,關於各個加載器的參數配置,可自行搜索之。
            {
                test: /\.css$/,
                //配置css的抽取器、加載器。'-loader'能夠省去
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader') 
            }, {
                test: /\.less$/,
                //配置less的抽取器、加載器。中間!有必要解釋一下,
                //根據從右到左的順序依次調用less、css加載器,前一個的輸出是後一個的輸入
                //你也能夠開發本身的loader喲。有關loader的寫法可自行谷歌之。
                loader: ExtractTextPlugin.extract('css!less')
            }, {
                //html模板加載器,能夠處理引用的靜態資源,默認配置參數attrs=img:src,處理圖片的src引用的資源
                //好比你配置,attrs=img:src img:data-src就能夠一併處理data-src引用的資源了,就像下面這樣
                test: /\.html$/,
                loader: "html?attrs=img:src img:data-src"
            }, {
                //文件加載器,處理文件靜態資源
                test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'file-loader?name=./fonts/[name].[ext]'
            }, {
                //圖片加載器,雷同file-loader,更適合圖片,能夠將較小的圖片轉成base64,減小http請求
                //以下配置,將小於8192byte的圖片轉成base64碼
                test: /\.(png|jpg|gif)$/,
                loader: 'url-loader?limit=8192&name=./img/[hash].[ext]'
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({ //加載jq
            $: 'jquery'
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendors', // 將公共模塊提取,生成名爲`vendors`的chunk
            chunks: ['index','list','about'], //提取哪些模塊共有的部分
            minChunks: 3 // 提取至少3個模塊共有的部分
        }),
        new ExtractTextPlugin('css/[name].css'), //單獨使用link標籤加載css並設置路徑,相對於output配置中的publickPath
        
        //HtmlWebpackPlugin,模板生成相關的配置,每一個對於一個頁面的配置,有幾個寫幾個
        new HtmlWebpackPlugin({ //根據模板插入css/js等生成最終HTML
            favicon: './src/img/favicon.ico', //favicon路徑,經過webpack引入同時能夠生成hash值
            filename: './view/index.html', //生成的html存放路徑,相對於path
            template: './src/view/index.html', //html模板路徑
            inject: 'body', //js插入的位置,true/'head'/'body'/false
            hash: true, //爲靜態資源生成hash值
            chunks: ['vendors', 'index'],//須要引入的chunk,不配置就會引入全部頁面的資源
            minify: { //壓縮HTML文件    
                removeComments: true, //移除HTML中的註釋
                collapseWhitespace: false //刪除空白符與換行符
            }
        }),
        new HtmlWebpackPlugin({ //根據模板插入css/js等生成最終HTML
            favicon: './src/img/favicon.ico', //favicon路徑,經過webpack引入同時能夠生成hash值
            filename: './view/list.html', //生成的html存放路徑,相對於path
            template: './src/view/list.html', //html模板路徑
            inject: true, //js插入的位置,true/'head'/'body'/false
            hash: true, //爲靜態資源生成hash值
            chunks: ['vendors', 'list'],//須要引入的chunk,不配置就會引入全部頁面的資源
            minify: { //壓縮HTML文件    
                removeComments: true, //移除HTML中的註釋
                collapseWhitespace: false //刪除空白符與換行符
            }
        }),
        new HtmlWebpackPlugin({ //根據模板插入css/js等生成最終HTML
            favicon: './src/img/favicon.ico', //favicon路徑,經過webpack引入同時能夠生成hash值
            filename: './view/about.html', //生成的html存放路徑,相對於path
            template: './src/view/about.html', //html模板路徑
            inject: true, //js插入的位置,true/'head'/'body'/false
            hash: true, //爲靜態資源生成hash值
            chunks: ['vendors', 'about'],//須要引入的chunk,不配置就會引入全部頁面的資源
            minify: { //壓縮HTML文件    
                removeComments: true, //移除HTML中的註釋
                collapseWhitespace: false //刪除空白符與換行符
            }
        }),

        new webpack.HotModuleReplacementPlugin() //熱加載
    ],
    //使用webpack-dev-server,提升開發效率
    devServer: {
        contentBase: './',
        host: 'localhost',
        port: 9090, //默認8080
        inline: true, //能夠監控js變化
        hot: true, //熱啓動
    }
};

好了,完成以上的這些配置以後,執行webpack打包命令完成項目打包。

此時,前往/dist/view目錄下查看生成的list.html文件,以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表頁</title>
    <meta name="description" content="基於webpack的前端工程化開發解決方案探索">
<link rel="shortcut icon" href="/dist/favicon.ico"><link href="/dist/css/vendors.css?02568e631b7717b7149a" rel="stylesheet"><link href="/dist/css/list.css?02568e631b7717b7149a" rel="stylesheet"></head>
<body>
    <div class="g-hd"></div>
    <div class="g-bd">
        <ul id="list"></ul>
    </div>
    <div class="g-ft"></div>
<script src="/dist/js/vendors.js?02568e631b7717b7149a"></script><script src="/dist/js/list.js?02568e631b7717b7149a"></script></body>
</html>

能夠看到生成的文件除了保留原模板中的內容之外,還根據入口文件list.js的定義,自動添加須要引入CSS與JS文件,以及favicon,同時還添加了相應的hash值。

執行webpack-dev-server啓動devServer,打開http://localhost:9090/dist/view/index.html就能夠進行正常的頁面預覽了。說明咱們的資源路徑生成也是沒有問題的。

好了,純靜態的webpack前端構建過程就是這樣了。然而你可能還有疑問。

  • 假如你是個懶人,可能會以爲目前的配置不夠智能,每增長一個頁面,就得再手動添加入口文件及模板配置。

  • 假如你是個全棧工程師或者以nodejs作中間層的開發者,你的模板不是純粹的html,可是又須要像html模板那樣能自動根據須要添加css與js文件。

還等什麼,快戳這裏吧——基於webpack的前端工程化開發之多頁站點篇(二)

相關文章
相關標籤/搜索