webpack 多頁面構建


目標:

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

配置文件編寫(webpack.config.js)

示例:

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) { var entries = { 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的配置主要包括以下幾大項目:

  • entry:js入口源文件

    • 多入口配置

      • 為了使用多入口文件,你可以給entry傳入一個對象。對象的key代表入口點名字,value代表入口點。當使用多入口點的時候,需要重載output.filename,否責每個入口點都寫入到同一個輸出文件里面了。使用[name]來得到入口點名字。

      • 例子:

         {
         	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:生成文件

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

    • 例子:

       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 熱加載腳本。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM