標籤:安裝 war 文章 支援 查看 hunk scss tor comm
說在開頭
上個月斷斷續續的在研究webpack的配置,但是很多網上的文章基本上都是只說了開發環境的配置,而忽略了生產環境的配置。大致研究了一下門路,然後就來寫一篇隨筆讓自己能在以後能有個地方可以做參考。
本文開始
我就假裝大家都是裝了node的情況下。
1、進入項目目錄,運行`npm init`按照步驟填寫最終產生`package.json`檔案,所有使用 npm 做依賴管理的項目,根目錄下都會有一個這個檔案,該檔案描述了項目的基本資料以及一些第三方依賴項(外掛程式)。詳細的使用說明可查閱[官網文檔],不過是英文的。 2、已知我們將使用 webpack 作為構建工具,那麼就需要安裝相應外掛程式,運行 `npm install webpack webpack-dev-server --save-dev` 來安裝兩個外掛程式。又已知我們將使用 React ,也需要安裝相應外掛程式,運行 `npm i react react-dom --save`來安裝兩個外掛程式。其中`i`是`install`的簡寫形式。安裝完成之後,查看`package.json`可看到多了`devDependencies`和`dependencies`兩項,根目錄也多了一個`node_modules`檔案夾。 3、`--save` 和 `--save-dev` 的區別`npm i`時使用`--save`和`--save-dev`,可分別將依賴(外掛程式)記錄到`package.json`中的`dependencies`和`devDependencies`下面。`dependencies`下記錄的是項目在運行時必須依賴的外掛程式,常見的例如`react` `jquery`等,即使項目打包好了、上線了,這些也是需要用的,否則程式無法正常執行。`devDependencies`下記錄的是項目在開發過程中使用的外掛程式,例如這裡我們開發過程中需要使用`webpack`打包,但是一旦項目打包發布、上線了之後,`webpack`就都沒有用了,可卸磨殺驢。延伸一下,我們的項目有`package.json`,其他我們用的項目如`webpack`也有`package.json`,見`./node_modules/webpack/package.json`,其中也有`devDependencies`和`dependencies`。當我們使用`npm i webpack`時,`./node_modules/webpack/package.json`中的`dependencies`會被 npm 安裝上,而`devDependencies`也沒必要安裝。 4、webpack.config.js為了提高學習效率,webpack 最最基礎的用法,就不再挨個示範了(推薦一個非常好的[入門文章],以及[更多資料])這裡我們把項目中的`webpack.config.js`這個設定檔詳細的講解一下,過程中也會照顧 0 基礎的同學。webpack.config.js 就是一個普通的 js 檔案,符合 commonJS 規範。最後輸出一個對象,即`module.exports = {...}`這個比較基礎,不過需要建立`./app/index.js`作為入口檔案,目前項目中只有這一個入口檔案。不過 webpack 支援多個入口檔案,可查閱文檔。輸出就是一個`bundle.js`,js 和 css 都在裡面,不過只有在開發環境下才用,發布代碼的時候,肯定不能只有這麼一個檔案,接下來會講到。
module針對不同類型的檔案,使用不同的`loader`,當然使用之前要安裝,例如`npm i style-loader css-loader --save-dev`。該項目代碼中,我們用到的檔案格式有:js/jsx 代碼、css/less 代碼、圖片、字型檔。less 是 css 的文法糖,可以更高效低冗餘的寫 css,不熟悉的朋友可去[官網]看看,非常簡單。在載入 css/less 時用到了`postcss`,主要使用`autoprefixer`功能,協助自動加 css3 的瀏覽器首碼,非常好用。編譯 es6 和 jsx 文法時,用到家喻戶曉的`babel`,另外還需增加一個`.babelrc`的設定檔。
plugins使用 html 模板(需要`npm i html-webpack-plugin --save-dev`),這樣可以將輸出的檔案名稱(如`./bundle.js`)自動注入到 html 中,不用我們自己手寫。手寫的話,一旦修改就需要改兩個地方。使用熱載入和自動開啟瀏覽器外掛程式
devServer對 webpack-dev-server 的配置
npm start在 package.json 中,輸入以下代碼,將這一串命令封裝為`npm start`,這樣就可以運行項目代碼了。
"scripts": {"start": "NODE_ENV=dev webpack-dev-server --progress --colors"} 代碼中`NODE_ENV=dev`代表當前是開發環境下,這裡的`"dev"`可被 js 代碼中的`process.env.NODE_ENV`得到並做一些其他處理。 5、定義環境全域變數以下定義,可使得代碼通過`__DEV__`得到當前是不是開發模式。
new webpack.DefinePlugin({__DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == ‘dev‘) || ‘false‘))})
開啟`./app/util/localStore.js`可以看到`if (__DEV__) { console.error(‘localStorage.getItem報錯, ‘, ex.message) }`,即只有開發環境下才提示error,發布之後就不會提示了。(因為發布的命令中用到`NODE_ENV=production`) 6、生產環境的配置 webpack.production.config.js開發環境下,可以不用考慮系統的效能,更多考慮的是如何增加開發效率。而發布系統時,就需要考慮發布之後的系統的效能,包括載入速度、緩衝等。下面介紹發布用配置代碼和開發用的不一樣的地方。發布到 `./build` 檔案夾中 : `path: __dirname + "/build",`
vendor將第三方依賴單獨打包。即將 node_modules 檔案夾中的代碼打包為 vendor.js 將我們自己寫的業務代碼打包為 app.js。這樣有助於緩衝,因為在項目維護過程中,第三方依賴不經常變化,而業務代碼會經常變化。
md5尾碼為每個打包出來的檔案都加md5尾碼,例如`"/js/[name].[chunkhash:8].js"`,可使檔案強緩衝。
分目錄打包出來的不同類型的檔案,放在不同目錄下,例片檔案將放在`img/`目錄下
Copyright自動為打包出來的代碼增加 copyright 內容
分模組`new webpack.optimize.OccurenceOrderPlugin(),`
壓縮代碼使用 Uglify 壓縮代碼,其中`warnings: false`是去掉代碼中的 warning
分離 css 和 js 檔案開發環境下,css 代碼是放在整個打包出來的那個 bundle.js 檔案中的,發布環境下當然不能混淆在一起,使用`new ExtractTextPlugin(‘/css/[name].[chunkhash:8].css‘),`將 css 代碼分離出來。 7、npm run build開啟`package.json`,查看以下代碼。`npm start`和`npm run build`分別是運行代碼和打包項目。另外,`"start"、"test"`可以不用`run`。
"scripts": {"start": "NODE_ENV=dev webpack-dev-server --progress --colors","build": "rm -rf ./build && NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors"},
這兩個命令主要有以下區別:
- 前者中預設使用 webpack.config.js 作為設定檔,而後者中強制使用 webpack.production.config.js 作為設定檔- 前者`NODE_ENV=dev`而後者`NODE_ENV=production`,標識不同的環境。而這個`"dev" "production"`可以在代碼中通過`process.env.NODE_ENV`擷取。
最小化壓縮 React以下配置可以告訴 React 當前是生產環境,請最小化壓縮 js ,即把開發環境中的一些提示、警告、判斷通通去掉,直流以下發布之後可用的代碼。
new webpack.DefinePlugin({‘process.env‘:{‘NODE_ENV‘: JSON.stringify(process.env.NODE_ENV)}}),
接下來把開發代環境的配置和生產環境的配置貼上
webpack.config.js
var path = require(‘path‘)var webpack = require(‘webpack‘)var HtmlWebpackPlugin = require(‘html-webpack-plugin‘);var OpenBrowserPlugin = require(‘open-browser-webpack-plugin‘);module.exports = { entry: path.resolve(__dirname, ‘app/index.js‘), output: { filename: "bundle.js" }, resolve: { extensions: [‘‘, ‘.js‘, ‘.jsx‘] }, module: { loaders: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: ‘babel‘ }, { test: /\.less$/, exclude: /node_modules/, loader: ‘style!css!postcss!less‘ }, { test: /\.css$/, exclude: /node_modules/, loader: ‘style!css!postcss‘ }, { test:/\.(png|gif|jpg|jpeg|bmp)$/i, loader:‘url-loader?limit=5000‘ }, // 限制大小5kb { test:/\.(png|woff|woff2|svg|ttf|eot)($|\?)/i, loader:‘url-loader?limit=5000‘} // 限制大小小於5k ] }, postcss: [ require(‘autoprefixer‘) //調用autoprefixer外掛程式,例如 display: flex ], plugins: [ // html 模板外掛程式 new HtmlWebpackPlugin({ template: __dirname + ‘/app/index.html‘ }), // 熱載入 new webpack.HotModuleReplacementPlugin(), // 開啟瀏覽器 new OpenBrowserPlugin({ url: ‘http://localhost:8080‘ }), // 可在業務js代碼中使用 __DEV__ 判斷是否是開發環境 (dev模式下可以提示錯誤、測試報告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == ‘dev‘) || ‘false‘)), }) ], devServer: { proxy: { // 凡是 `/api` 開頭的 http 請求,都會被代理到 localhost:3000 上,由 koa 提供 mock 資料。 // koa 代碼在 ./mock 目錄中,啟動命令為 npm run mock ‘/api‘: { target: ‘http://localhost:3000‘, secure: false } }, colors: true, // 終端舒服為彩色 historyApiFallback: true, //不跳轉,在開發單頁應用時非常有用,它依賴於HTML5 history API,如果設定為true,所有的跳轉將指向index.html inline: true, // 即時重新整理 hot: true, // 使用熱載入外掛程式 HotModuleReplacementPlugin }}
webpack.production.config.js
var pkg = require(‘./package.json‘)var path = require(‘path‘)var webpack = require(‘webpack‘);var HtmlWebpackPlugin = require(‘html-webpack-plugin‘);var ExtractTextPlugin = require(‘extract-text-webpack-plugin‘);module.exports = { entry: { app: path.resolve(__dirname, ‘app/index.js‘), // 將 第三方依賴(node_modules中的) 單獨打包 vendor: Object.keys(pkg.dependencies) }, output: { path: __dirname + "/build", filename: "/js/[name].[chunkhash:8].js" }, resolve:{ extensions:[‘‘, ‘.js‘,‘.jsx‘] }, module: { loaders: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: ‘babel‘ }, { test: /\.less$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract(‘style‘, ‘css!postcss!less‘) }, { test: /\.css$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract(‘style‘, ‘css!postcss‘) }, { test:/\.(png|gif|jpg|jpeg|bmp)$/i, loader:‘url-loader?limit=5000&name=img/[name].[chunkhash:8].[ext]‘ }, { test:/\.(png|woff|woff2|svg|ttf|eot)($|\?)/i, loader:‘url-loader?limit=5000&name=fonts/[name].[chunkhash:8].[ext]‘} ] }, postcss: [ require(‘autoprefixer‘) ], plugins: [ // webpack 內建的 banner-plugin new webpack.BannerPlugin("Copyright by [email protected]"), // html 模板外掛程式 new HtmlWebpackPlugin({ template: __dirname + ‘/app/index.html‘ }), // 定義為生產環境,編譯 React 時壓縮到最小 new webpack.DefinePlugin({ ‘process.env‘:{ ‘NODE_ENV‘: JSON.stringify(process.env.NODE_ENV) } }), // 為組件分配ID,通過這個外掛程式webpack可以分析和優先考慮使用最多的模組,並為它們分配最小的ID new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { //supresses warnings, usually from module minification warnings: false } }), // 分離CSS和JS檔案 new ExtractTextPlugin(‘/css/[name].[chunkhash:8].css‘), // 提供公用代碼 new webpack.optimize.CommonsChunkPlugin({ name: ‘vendor‘, filename: ‘/js/[name].[chunkhash:8].js‘ }), // 可在業務 js 代碼中使用 __DEV__ 判斷是否是dev模式(dev模式下可以提示錯誤、測試報告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == ‘dev‘) || ‘false‘)) }) ]}
搭建 webpack + React 開發環境