webpack 多頁面構建

目標javascript

一、基於webpack支持react多頁面構建(不用gulp,gulp-webpack 構建速度太慢[3]), generator-react-webpack 對單頁面支持很好,但對多頁面,須要改造
二、提升開發人員的效率
三、對項目進行足夠的性能優化
四、提升構建的效率css

webpack.config.js(示例)html

var path = require('path');
var glob = require('glob');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var node_dir = path.join(__dirname, './node_modules/');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var getEntry = function(globPath) { 
        vendor: ['jquery','react','react-dom','./src/app'] // 類庫
    };
    glob.sync(globPath).forEach(function(entry) {
        var pathname = entry.split('/').splice(-2).join('/').split('.')[0];
        entries[pathname] = [entry];
    });
    console.log(entries);
    return entries;
};
// 判斷是不是在當前生產環境
var isProduction = process.env.NODE_ENV === 'production';
var entries = getEntry('./src/view/*/*.jsx');
var chunks = Object.keys(entries);
module.exports = {
    entry: entries,
    output: {
        path: path.join(__dirname, './dist'),
        filename: isProduction ?'js/[name].[hash:8].js':'js/[name].js',
        publicPath: '/dist/',
        chunkFilename: 'chunk/[name].chunk.js'
    },
    module: {
        noParse:[
            /*path.join(node_dir,'./react/dist/react.min.js'),
            path.join(node_dir,'./jquery/dist/jquery.min.js'),
            path.join(node_dir,'./react-dom/dist/react-dom.min.js')*/
        ],
        loaders: [{
            test: /\.jsx?$/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'react']
            },
            exclude: node_dir
        }, {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract('style', 'css')
        }, {
            test: /\.less$/,
            loader: ExtractTextPlugin.extract('style', 'css!less')
        }, {
            test: /\.(png|jpe?g|gif)$/,
            loader: 'url?limit=8192&name=img/[hash:8].[ext]'
        }, {
            //文件加載器,處理文件靜態資源
            test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
            loader: 'file?limit=10000&name=fonts/[hash:8].[ext]'
        }]
    },
    resolve: {
        extensions: ['', '.js', '.jsx', '.json'],
        alias: {
            mod: node_dir
        }
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery', // 使jquery變成全局變量,不用在本身文件require('jquery')了
            jQuery: 'jquery',
            React: 'react',
            ReactDOM: 'react-dom'
        }),
        // 類庫統一打包生成一個文件
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: isProduction ? 'js/vendor.[hash:8].js':'js/vendor.js',
            minChunks: 3 // 提取使用3次以上的模塊,打包到vendor裏
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        }),
        new ExtractTextPlugin(isProduction ? 'css/[name].[hash:8].css':'css/[name].css')
    ],
    devtool: isProduction ? null : 'source-map'
};
// 生成HTML文件
chunks.forEach(function(pathname) {
    if (pathname == 'vendor') {
        return;
    }
    var conf = {
        title: 'My App',
        filename: isProduction? '../view/' + pathname + '.html' : pathname + '.html',
        template: './src/template.html',
        inject: 'body',
        minify: {
            removeComments: true,
            collapseWhitespace: false
        }
    };
    if (pathname in module.exports.entry) {
        conf.chunks = ['vendor', pathname];
        conf.hash = false;
    }
    module.exports.plugins.push(new HtmlWebpackPlugin(conf));
});

Webpack說明相關知識說明java

entry:js入口源文件node

多入口配置
爲了使用多入口文件,你能夠給entry傳入一個對象。對象的key表明入口點名字,value表明入口點。當使用多入口點的時候,須要重載output.filename,否責每一個入口點都寫入到同一個輸出文件裏面了。使用[name]來獲得入口點名字。react

例子:jquery

{
     entry: {
         a: "./a",
         b: "./b",
         //支持數組形式,將加載數組中的全部模塊,但以最後一個模塊做爲輸出
         //該方法能夠添加多個彼此不互相依賴的文件
         c: ["./c", "./d"]
     },
     output: {
         path: path.join(__dirname, "dist"),
         filename: "[name].entry.js" // a.enrty.js, b.enrty.js, c.entry.js
     }
 }

output:生成文件webpack

output參數是個對象,定義了輸出文件的位置及名字.git

例子:github

output: {
     path: "dist/js/page",
     publicPath: "/output/",
     filename: "[name].bundle.js"
 }

path: 打包文件存放的絕對路徑
publicPath: 網站運行時的訪問路徑
filename:打包後的文件名
module:模塊加載器

在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,圖片等靜態文件都是模塊,不一樣模塊的加載是經過模塊加載器(webpack-loader)來統一管理的。loaders之間是能夠串聯的,一個加載器的輸出能夠做爲下一個加載器的輸入,最終返回到JavaScript上。

例子:

module: {
     //加載器配置
     loaders: [
         //.css 文件使用 style-loader 和 css-loader 來處理
         { 
             test: /\.css$/, 
             loader: 'style-loader!css-loader' 
         },
         //.js 文件使用 jsx-loader 來編譯處理
         { 
             test: /\.js$/, 
             loader: 'jsx-loader?harmony' 
         },
         //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理
         { 
             test: /\.scss$/, 
             loader: 'style!css!sass?sourceMap'
         },
         //圖片文件使用 url-loader 來處理,小於8kb的直接轉爲base64
         { 
             test: /\.(png|jpg)$/, 
             loader: 'url-loader?limit=8192'
         }
     ]
 }

多個loader能夠用在同一個文件上而且被鏈式調用。鏈式調用時從右到左執行且loader之間用「!」來分割。

模塊加載器(loader)自身能夠根據傳入不一樣的參數進行配置。

resolve:文件路徑的指向

webpack在構建包的時候會按目錄的進行文件的查找,resolve屬性中的extensions數組中用於配置程序能夠自行補全哪些文件後綴:

例子:

resolve: {
     //查找module的話從這裏開始查找
     root: '/pomy/github/flux-example/src', //絕對路徑
     //自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名
     extensions: ['', '.js', '.json', '.scss'],
     //模塊別名定義,方便後續直接引用別名,無須多寫長長的地址
     alias: {
         AppStore : 'js/stores/AppStores.js',//後續直接 require('AppStore') 便可
         ActionType : 'js/actions/ActionType.js',
         AppAction : 'js/actions/AppAction.js'
     }
 }

plugins:插件,比loader更強大,能使用更多webpack的api

插件通常都是用於輸出bundle的node模塊。例如,uglifyJSPlugin獲取bundle.js而後壓縮和混淆內容以減少文件體積。相似的extract-text-webpack-plugin內部使用css-loader和style-loader來收集全部的css到一個地方最終將結果提取結果到一個獨立的」styles.css「文件,而且在html裏邊引用style.css文件。

例子:

var ExtractTextPlugin = require("extract-text-webpack-plugin");
 
 module: {
     loaders: [
         {
             test: /\.css$/,
             loader: ExtractTextPlugin.extract("style-loader", "css-loader")
         },
         {
             test: /\.less$/,
             loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
         }
     ]
 },
 plugins: [
     new ExtractTextPlugin("[name].css")
 ]

code-splitting 插件CommonsChunkPlugin

將屢次引用的模塊單獨打包

new webpack.optimize.CommonsChunkPlugin({
     name: 'vendor',
     filename: isProduction ? 'js/vendor.[hash:8].js':'js/vendor.js',
     minChunks: 3 // 提取使用3次以上的模塊,打包到vendor裏
 })

多頁面 html 生成插件 html-webpack-plugin

例子:

var HtmlWebpackPlugin = require('html-webpack-plugin');
 chunks.forEach(function(pathname) {
 if (pathname == 'vendor') {
     return;
 }
 var conf = {
     title: 'My App',
     filename: isProduction? '../view/' + pathname + '.html' : pathname + '.html',
     template: './src/template.html',
     inject: 'body',
     minify: {
         removeComments: true,
         collapseWhitespace: false
     }
 };
 if (pathname in module.exports.entry) {
     conf.chunks = ['vendor', pathname];
     conf.hash = false;
 }
 module.exports.plugins.push(new HtmlWebpackPlugin(conf));
});

src目錄下有個template.html文件,無需引入任何css和js,webpack會自動幫咱們打包引入,<%= htmlWebpackPlugin.options.title %>讀取配置好的頁面標題

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8" />
     <title> <%= htmlWebpackPlugin.options.title %> </title>
 </head>
 <body>
     <div id="app"></div>
 </body>
 </html>

最終經過打包,會生成對應入口的html文件,
好比src/view/index/index.js會生成view/index/index.html

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title> My App </title>
     <link href="/dist/css/vendor.abf9657f.css" rel="stylesheet">
     <link href="/dist/css/index/index.abf9657f.css" rel="stylesheet">
 </head>
 <body>
     <div id="app"></div>
     <script type="text/javascript" src="/dist/js/vendor.abf9657f.js"></script>
     <script type="text/javascript" src="/dist/js/index/index.abf9657f.js"></script>
 </body>
 </html>

你會發現相關資源文件都自動引入了,十分便捷。

webpack 經常使用命令

webpack 最基本的啓動webpack命令
webpack -w 提供watch方法,實時進行打包更新
webpack -p 對打包後的文件進行壓縮
webpack -d 提供SourceMaps,方便調試
webpack --colors 輸出結果帶彩色,好比:會用紅色顯示耗時較長的步驟
webpack --profile 輸出性能數據,能夠看到每一步的耗時
webpack --display-modules 默認狀況下 node_modules 下的模塊會被隱藏,加上這個參數能夠顯示這些被隱藏的模塊
webpack dev server

配置示例:

var webpack = require('webpack');
 var WebpackDevServer = require('webpack-dev-server');
 var config = require('./webpack.config.js');
 
 for (var i in config.entry) {
     // 每一個入口文件加入 client websocket 熱加載腳本
     config.entry[i].unshift(
         "webpack-dev-server/client?http://127.0.0.1:3000/", 
         "webpack/hot/only-dev-server"
     );
 }
 config.module.loaders.unshift({
     test: /\.jsx?$/,
     loader: 'react-hot',
     exclude: /node_modules/
 });
 config.plugins.push(new webpack.HotModuleReplacementPlugin());
 new WebpackDevServer(webpack(config), {
     publicPath: config.output.publicPath,
     hot: true,
     historyApiFallback: true,
     stats: { colors: true }
     }).listen(3000, '127.0.0.1', function (err, result) {
     if (err) {
         console.log(err);
     }
     console.log('server start');
 });

用處

開啓服務器調試環境
解決如下兩個問題:
webpack --watch 打包速度慢
不能作到hot replace
配置

Content Base

若是不進行設定的話,服務器伺服默認是在當前目錄下。

命令行設置 webpack-dev-server --content-base build/

webpack 配置

devServer: {
     contentBase: './src/',
     historyApiFallback: true,
     hot: true,
     port: defaultSettings.port,
     publicPath: '/assets/',
     noInfo: false
 }
publicPath

webpack server 伺服的 bundle 是在內存中的,其相對路徑由 publicPath 字段指定。
若是用以上的配置,bundle 能夠經過地址 localhost:8080/assets/bundle.js 訪問到。(注意:訪問的不是output目錄下的文件而是內存中的數據!)
自動更新和熱替換

配置:

var config = require("./webpack.config.js");
 config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server");
 var compiler = webpack(config);
 var server = new webpackDevServer(compiler, {
     hot: true
     ...
 });
 server.listen(8080);

關鍵配置: config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server");

在每一個入口文件注入 client websocket 熱加載腳本。

相關文章
相關標籤/搜索