webpack2配置

詳細的配置能夠參考官網:https://doc.webpack-china.org/guides/css

一開始作項目時都是直接從組裏前輩搭建好的腳手架開始寫代碼,到後來本身寫新項目時又是拷貝以前的工程做爲腳手架開始。對於腳手架自己卻不甚瞭解,不只不思考爲何更是沒有改進的想法,怪不得工做滿一年了卻總以爲本身的技術水平在原地踏步,就是沒有總結和思考。前端

目前組裏的技術棧都是使用vue+koa,使用webpack的好處一是方便寫vue的單文件組件,二是打包文件方便生產部署再加上能無所顧慮的應用語言的新特性。vue

1. 配置文件node

官方文檔推薦寫webpack配置文件時,先寫出一個基本配置文件(base)包含入口、輸出等,再根據開發/生產環境所須要插件的不一樣,利用webpack-merge生成三個配置文件: dev、prod、analyzewebpack

package.json 依賴參考git

"devDependencies": {
    "babel-core": "^6.18.2",
    "babel-loader": "^7.1.1",
    "babel-preset-es2015": "^6.18.0",
    "css-loader": "^0.28.4",
    "koa-webpack-dev-middleware": "^1.4.0",
    "koa-webpack-hot-middleware": "^1.0.3",
    "less": "^2.7.1",
    "less-loader": "^4.0.5",
    "style-loader": "^0.18.2",
    "url-loader": "^0.5.7",
    "vue-loader": "^12.2.2",
    "webpack": "^3.3.0",
    "webpack-bundle-analyzer": "^2.8.3",
    "webpack-dev-middleware": "^1.11.0",
    "webpack-dev-server": "^2.6.1",
    "webpack-hot-middleware": "^2.13.1",
    "webpack-koa-hot-middleware": "^0.1.2",
    "webpack-manifest-plugin": "^1.2.1",
    "webpack-merge": "^4.1.0"
  }

 

webpack.config.base.jsgithub

 1 'use strict'
 2 let path = require('path');
 3 let webpack = require('webpack');
 4 let WebpackManifestPlugin = require("webpack-manifest-plugin");
 5 
 6 module.exports = {
 7     output: {
 8         path: path.resolve(__dirname, '..', 'build')
 9     },
10     resolve: {
11         extensions: ['.js', '.vue'],
12         modules: ['node_modules'],
13         alias: {
14             'leafletCSS': 'leaflet/dist/leaflet.css',
15             'leaflet$': 'leaflet/dist/leaflet.js',
16             'vue$': 'vue/dist/vue.min.js',
17             'vue-resource$': 'vue-resource/dist/vue-resource.min.js'
18         }
19     },
20     module: {
21         rules: [
22             {
23                 test: /\.vue$/,
24                 loader: 'vue-loader',
25             },
26             {
27                 test: /\.js$/,
28                 exclude: /(node_modules|bower_components)/,
29                 use: {
30                     loader: 'babel-loader',
31                     options: {
32                         presets: ['es2015']
33                     }
34                 }
35             },
36             {
37                 test: /\.css$/,
38                 use: [
39                     'style-loader',
40                     'css-loader'
41                 ]
42             },
43             {
44                 test: /\.(png|jpe?g|gif|svg|woff2?|ttf|otf)(\?.*)?$/,
45                 loader: 'url-loader',
46             },
47             {
48                 test: /\.less$/,
49                 use: [
50                     'style-loader',
51                     'css-loader',
52                     'less-loader'
53                 ]
54             }
55         ]
56     },
57     plugins: [
58         new WebpackManifestPlugin(),
59         new webpack.optimize.CommonsChunkPlugin({
60             name: 'vendor',
61             minChunks: function (module) {
62                 // this assumes your vendor imports exist in the node_modules directory
63                 return module.context && module.context.indexOf('node_modules') !== -1;
64             }
65         }),
66         new webpack.optimize.CommonsChunkPlugin({
67             name: 'common',
68             chunks: ['qq', 'navi', 'log', 'guide', 'apply', 'voice', 'pianhang', 'dynamic'], //這裏輸入須要提取公共代碼的entry
69             minChunks: 2
70         }),
71         //CommonChunksPlugin will now extract all the common modules from vendor and main bundles
72         new webpack.optimize.CommonsChunkPlugin({
73             name: 'manifest', //But since there are no more common modules between them we end up with just the runtime code included in the manifest file
74         }),
75     ]
76 }

第16行代碼能夠參考這裏這裏,默認NPM包導出的是運行時構建,Vue2的運行時構建不支持單文件組件的templateweb

第58行的 WebpackManifestPlugin 做用是將輸出文件名保存在文件中 (當輸出文件名帶 chunkhash 時頗有用,參考這裏)npm

第59~74行的 CommonsChunkPlugin 做用是從打包後的 bundle 文件中提取公共模塊,將 npm install 的公共模塊和業務代碼分開,這樣瀏覽器就能夠一直緩存公共模塊的bundle,參考這裏。第一個 CommonsChunkPlugin 做用是將 node_modules 裏的模塊提取到 vendor.js 裏;第二個 CommonsChunkPlugin 做用是將 entry 裏的公共代碼提取出來放在 common.js 裏,參考這裏;第三個 CommonsChunkPlugin 做用是將 webpack 運行時代碼放在 manifest.js 裏json

 

webpack.config.dev.js

 1 "use strict"
 2 let webpack = require('webpack');
 3 let merge = require('webpack-merge');
 4 let base_config = require('./webpack.config.base');
 5 
 6 module.exports = merge(base_config, {
 7     entry: {
 8         qq: ['./src/qq/qq.js', 'webpack-hot-middleware/client'],
 9         navi: ['./src/navi/navi.js', 'webpack-hot-middleware/client'],
10         log: ['./src/log/log.js', 'webpack-hot-middleware/client'],
11         guide: ['./src/guide/guide.js', 'webpack-hot-middleware/client'],
12         apply: ['./src/apply/apply.js', 'webpack-hot-middleware/client'],
13         voice: ['./src/voice/voice.js', 'webpack-hot-middleware/client'],
14         pianhang: ['./src/pianhang/pianhang.js', 'webpack-hot-middleware/client'],
15         dynamic: ['./src/dynamic/dynamic.js', 'webpack-hot-middleware/client']
16     },
17     output: {
18         filename: '[name].js',
19     },
20     devtool: '#eval-source-map',
21     plugins: [
22         new webpack.HotModuleReplacementPlugin(),
23     ]
24 });

第 20 行設置source-map,方便用瀏覽器查看源代碼

 

webpack.config.prod.js

 1 "use strict"
 2 let webpack = require('webpack');
 3 let merge = require('webpack-merge');
 4 let base_config = require('./webpack.config.base');
 5 
 6 module.exports = merge(base_config, {
 7     entry: {
 8         qq: ['./src/qq/qq.js'],
 9         navi: ['./src/navi/navi.js'],
10         log: ['./src/log/log.js'],
11         guide: ['./src/guide/guide.js'],
12         apply: ['./src/apply/apply.js'],
13         voice: ['./src/voice/voice.js'],
14         pianhang: ['./src/pianhang/pianhang.js'],
15         dynamic: ['./src/dynamic/dynamic.js'],
16     },
17     output: {
18         filename: '[name].[chunkhash].js',
19     },
20     plugins: [
21         new webpack.optimize.UglifyJsPlugin()
22     ]
23 });

第 21 行 UglifyJsPlugin 的做用是壓縮、混淆代碼

 

webpack.config.analyze.js

 1 "use strict"
 2 
 3 let webpack = require('webpack');
 4 let merge = require('webpack-merge');
 5 var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 6 let prod_config = require('./webpack.config.prod');
 7 
 8 module.exports = merge(prod_config, {
 9     plugins: [
10         new BundleAnalyzerPlugin()
11     ]
12 });

analyze 文件的做用利用 webpack-bundle-analyzer 插件分析打包狀況,

webpack --config ./config/webpack.config.analyze.js

運行結果以下:

 

webpack的配置文件自定義程度很高,因此在參考他人配置時最好能弄清楚爲何要這樣寫

 

2. webpack-dev-server 

在開發過程當中另外一個重要的東西是 webpack-dev-server,它的做用是當你改動源代碼後能自動從新打包,再加上 webpack 的HMR-模塊熱替換特性,這樣改動代碼就能直接在瀏覽器裏看到效果,省卻了代碼手動打包+刷新瀏覽器的步驟。使用 webpack-dev-server 有 CLI 和 API 兩種使用方法。

CLI 方式設置 dev 文件中的 HotModuleReplacementPlugin 和 devServer 啓用 HMR。啓動的命令爲:

webpack-dev-server --config ./config/webpack.config.dev.js

API 方式直接在命令裏設置參數,如:(這裏用到了 Unix Domin Socket,也能夠直接指定 ip和端口)

webpack-dev-server --config config/webpack.dev.config.js --public 0.0.0.0:8056 --progress --inline --hot --socket .dev-shared/sockets/webpack.sock

webpack-dev-server 的方式配置簡單,缺點是引入 bundle 比較麻煩,須要指定其它端口

 

3. webpack-dev-middleware 

上述配置文件就是使用的該方法,須要有 koa-webpack-dev-middleware、koa-webpack-hot-middleware(熱更新)。而後在 index.js 裏寫:

1 if (process.env.NODE_ENV == 'dev') {
2     let webpack = require('webpack');
3     let webpackConfig = require('./config/webpack.config.dev.js');
4     let webpackDevMiddleware = require('koa-webpack-dev-middleware');
5     let webpackHotMiddleware = require('koa-webpack-hot-middleware');
6     let compiler = webpack(webpackConfig);
7     app.use(webpackDevMiddleware(compiler));
8     app.use(webpackHotMiddleware(compiler));
9 }

這樣就不須要經過額外的端口獲取 bundle 文件了,注意這裏是 koa 環境

 

4. 如何在前端框架裏引入 bundle

因爲 webpack prod 配置文件裏使用了 chunkhash 做爲 bundle 的名字的一部分,修改業務代碼,chunkhash 會發生改變,因此須要經過一些方法自動將 bundle 名字注入到前端頁面裏:

第一種方法是經過在後端 controller 裏讀取 manifest.json 裏的內容,而後經過模板引擎,注入到頁面裏,例如 nunjucks:

{% for path in paths %}
    <script src="{{path}}"></script>
{% endfor %}

第二種方法是拓展模板引擎命令,例如 xtpl:

{{{ xScript('manifest.js') }}}
{{{ xScript('vendor.js') }}}
{{{ xScript('common.js') }}}
{{{ xScript('apply.js') }}}

xtpl 命令拓展現例 xtpl.ext.js :

 1 let xtplApp = require('xtpl/lib/koa');
 2 let xtpl = require('xtpl/lib/xtpl');
 3 let XTemplate = xtpl.XTemplate;
 4 
 5 XTemplate.addCommand('xScript', function(scope, option){
 6     let name = option.params[0];
 7     if (process.env.NODE_ENV !== 'dev') {
 8         let assets_map = require('./manifest');
 9         name = assets_map[name];
10     }
11     return '<script src="' + name + '" ></script>';
12 });
13 
14 module.exports = xtplApp;

而後在 index.js 裏

let xtpl = require('./extensions/xtpl.ext');

 

注意引入 bundle 的時候要注意引入順序:manifest > vendor > common > entry,不然可能會報 ReferenceError: webpackJsonp is not defined 錯誤,還要注意要有 .babelrc 文件:

{
    "presets": ["es2015"]
}

不然會報 SyntaxError: Unexpected token: name (xxxxxx) from Uglify plugin 之類的錯誤,沒法識別語言新特性

相關文章
相關標籤/搜索