源碼地址:https://github.com/remmlqw/we...
注意:本文是從 Webpack3 搭建 兼容 Webpack4css
新建項目
一、新建一個文件夾html
npm init
一直回車,最後yes,生成package.json前端
二、文件夾中新建如下文件node
src --源碼 index.html --入口首頁 webpack.config.js --webpack開發環境配置 webpack.production.config.js --webpack生產環境配置
下載依賴包
先下載幾個基本的包,後續還會用到其餘包。react
打包工具
webpack webpack
輔助開發的服務器(該服務器能熱加載代碼,自動刷新頁面,代理服務器解決前端開發時跨域問題)
webpack-dev-server git
在webpack 3中,webpack自己和它的CLI之前都是在同一個包中,但在第4版中,他們已經將二者分開來更好地管理它們。因此還要安裝:
webpack-cli
注:這裏除了本地安裝外,還需全局安裝 npm i webpack-cli -g
es6
react用到es6語法,因此要安裝es6轉碼器babel相關的包
babel-core
babel-loader
babel-preset-env
babel-preset-reactgithub
webpack須要處理樣式文件打包的處理器
css-loader
style-loader
less-loaderweb
webpack須要處理圖片文件打包的處理器
file-loader
url-loader
以上包的下載使用 npm i XXX --save-dev
--save-dev 是寫入開發環境的依賴
react項目的兩個基礎包
react
react-dom
這兩個包下載使用 npm i XXX --save
--save 是寫入生產環境的依賴
package.json中的scripts
在package.json中的scripts加上兩個key
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "cross-env NODE_ENV=dev webpack-dev-server --inline --progress --colors --mode development", "build": "cross-env NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors --mode production" },
這裏須要安裝的一個包 npm i cross-env --save-dev
有何用?
windows不支持 NODE_ENV=development
的設置方式,這個包可以提供一個設置環境變量的scripts,讓你可以以unix方式設置環境變量,而後在windows上也能兼容運行。cross-env
讓這一切變得簡單,不一樣平臺使用惟一指令,無需擔憂跨平臺問題。
--progress
顯示打包過程當中的進度--colors
打包信息帶有顏色顯示--inline
自動刷新的配置--mode development/production
webpack 4引入了生產和開發模式,自動根據開發和生產兩種模式進行優化
webpack --config ./webpack.production.config.js
這個命令是制定webpack的配置文件,由於默認的是webpack.config.js
,而這裏是打包命令,應該使用webpack.production.config.js
。
開發環境配置 --webpack.config.js
先上完整代碼
const path=require('path'); const webpack = require('webpack') var HtmlWebpackPlugin = require('html-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); // 配置文件的內容須要經過module.exports暴露 module.exports = { // 配置須要打包的入口文件,值能夠是字符串、數組、對象。 // 1. 字符串: entry: './entry' // 2. 字符串: entry:[ './entry1','entry2'] (多入口) // 3. 對象: entry: {alert/index': path.resolve(pagesDir, `./alert/index/page`)} // 多入口書寫的形式應爲object,由於object,的key在webpack裏至關於此入口的name, entry : './src/js/index.js', output : { // 輸出文件配置,output 輸出有本身的一套規則,經常使用的參數基本就是這三個 // path: 表示生成文件的根目錄 須要一個**絕對路徑** path僅僅告訴Webpack結果存儲在哪裏 path : path.resolve(__dirname,'dist'), // filename 屬性表示的是如何命名出來的入口文件 filename : './js/bundle.js' }, resolve: { //自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名 extensions: ['*', '.js', '.json', '.less','.jsx'], //模塊別名定義,方便後續直接引用別名,無須多寫長長的地址 alias: { '@components': path.resolve(__dirname,'src/js/components') } }, module : { // 這裏就是Loader,經過Loader,webpack可以針對每一種特定的資源作出相應的處理 // 1.test參數用來指示當前配置項針對哪些資源,該值應是一個條件值(condition)。 // 2.exclude參數用來剔除掉須要忽略的資源,該值應是一個條件值(condition)。 // 3.include參數用來表示本loader配置僅針對哪些目錄/文件,該值應是一個條件值(condition)。 // 而include參數則用來指示目錄;注意同時使用這二者的時候,其實是and的關係。 // 4.use參數,用來指示用哪一個或哪些loader來處理目標資源。 rules : [ { test: /\.(js|jsx)$/, use : { loader : "babel-loader", options : { presets : ['env','react'] } }, exclude : /node_modules/ }, { test: /\.less$/, exclude: /node_modules/, use : [{loader : "style-loader"},{loader : "css-loader"},{loader : "less-loader"}] }, { test : /\.css$/, use : [{loader : "style-loader"},{loader : "css-loader"}] }, { test: /\.(png|gif|jpg|jpeg|bmp)$/i, use : { loader : 'url-loader', options : { limit : '8192' } } }, { test: /\.(woff|woff2|svg|ttf|eot)($|\?)/i, use: { loader: 'url-loader', options: { limit: '8192' } } } ] }, plugins: [ // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + '/index.html' }), // 熱加載插件 new webpack.HotModuleReplacementPlugin(), // 打開瀏覽器 new OpenBrowserPlugin({ url: 'http://localhost:8080' }), // 可在業務 js 代碼中使用 __DEV__ 判斷是不是dev模式(dev模式下能夠提示錯誤、測試報告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == 'dev') || 'false')) }), ], //咱們在這裏對webpack-dev-server進行配置 devServer: { contentBase:"./",// 本地服務器在哪一個目錄搭建頁面,通常咱們在當前目錄便可; historyApiFallback:true,//當咱們搭建spa應用時很是有用,它使用的是HTML5 History Api,任意的跳轉或404響應能夠指向 index.html 頁面; inline:true,//用來支持dev-server自動刷新的配置,webpack有兩種模式支持自動刷新,一種是iframe模式,一種是inline模式;使用iframe模式是不須要在devServer進行配置的,只需使用特定的URL格式訪問便可;不過咱們通常仍是經常使用inline模式,在devServer中對inline設置爲true後,當咱們啓動webpack-dev-server時仍要須要配置inline才能生效 hot:true,// 啓動webpack熱模塊替換特性,這裏是個坑 port:8080,//配置服務端口號 host:'localhost',//服務器的IP地址,可使用IP也可使用localhost compress:true,//服務端壓縮是否開啓 } }
相關參數配置的說明已經寫在代碼的註釋裏。
這裏對於上面使用的插件我在作一下說明:
html-webpack-plugin
:html-webpack-plugin能夠根據你設置的模板,在每次運行後生成對應的模板文件,同時所依賴的CSS/JS也都會被引入,若是CSS/JS中含有hash值,則html-webpack-plugin生成的模板文件也會引入正確版本的CSS/JS文件。詳細介紹https://www.npmjs.com/package...
webpack.HotModuleReplacementPlugin
:模塊熱替換(HMR - Hot Module Replacement)功能會在應用程序運行過程當中替換、添加或刪除模塊,而無需從新加載整個頁面。主要是經過如下幾種方式,來顯著加快開發速度:
保留在徹底從新加載頁面時丟失的應用程序狀態。
只更新變動內容,以節省寶貴的開發時間。
調整樣式更加快速 ,幾乎至關於在瀏覽器調試器中更改樣式。
詳細介紹https://doc.webpack-china.org...
open-browser-webpack-plugin
: 則在webpack 啓動成功後會打開瀏覽器。詳細介紹https://www.npmjs.com/package...
webpack.DefinePlugin
: 可在業務 js 代碼中使用 DEV 判斷是不是dev模式。詳細介紹https://doc.webpack-china.org...
好比
if(__DEV__) { console.log("如今是開發環境"); } else { console.log("如今是生產環境"); }
這裏須要額外安裝的包:
html-webpack-plugin
open-browser-webpack-plugin
生產環境配置 --webpack.production.config.js
一樣的,先上完整代碼:
var path = require('path') var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var autoprefixer = require('autoprefixer'); var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { entry: { app: path.resolve(__dirname, './src/js/index.js'), // 將 第三方依賴 單獨打包 vendor: ['react', 'react-dom'] }, output: { path: __dirname + "/dist", // filename 屬性表示的是如何命名出來的入口文件,規則是一下三種: // [name] 指代入口文件的name,也就是上面提到的entry參數的key,所以,咱們能夠在name裏利用/,便可達到控制文件目錄結構的效果。 // [hash],指代本次編譯的一個hash版本,值得注意的是,只要是在同一次編譯過程當中生成的文件,這個[hash].js //的值就是同樣的;在緩存的層面來講,至關於一次全量的替換。 filename: "js/[name].[chunkhash:8].js", // publicPath 參數表示的是一個URL 路徑(指向生成文件的跟目錄),用於生成css/js/圖片/字體文件 // 等資源的路徑以確保網頁能正確地加載到這些資源. // 「publicPath」項則被許多Webpack的插件用於在生產模式下更新內嵌到css、html文件裏的url值. // 例如,在localhost(即本地開發模式)裏的css文件中邊你可能用「./test.png」這樣的url來加載圖片, // 可是在生產模式下「test.png」文件可能會定位到CDN上而且你的Node.js服務器多是運行在HeroKu上邊的。 // 這就意味着在生產環境你必須手動更新全部文件裏的url爲CDN的路徑。 //開發環境:Server和圖片都是在localhost(域名)下 //.image { // background-image: url('./test.png'); //} // 生產環境:Server部署下HeroKu可是圖片在CDN上 //.image { // background-image: url('https://someCDN/test.png'); //} publicPath: './' }, resolve: { //自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名 extensions: ['*', '.js', '.json', '.less','.jsx'], //模塊別名定義,方便後續直接引用別名,無須多寫長長的地址 alias: { '@components': path.resolve(__dirname,'src/js/components') } }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ['env', 'react'] } } }, { test: /\.less$/, exclude: /node_modules/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader', 'less-loader'] }) }, { test: /\.css$/, // exclude: /node_modules/, 刪掉次行 否則打包會報錯 由於antd.css 在node_modules中 use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader'] }) }, { test: /\.(png|gif|jpg|jpeg|bmp)$/i, use: { loader: 'url-loader', options: { limit: '8192', outputPath: 'images/', publicPath : '/images' } } }, { test: /\.(woff|woff2|svg|ttf|eot)($|\?)/i, use: { loader: 'url-loader', options: { limit: '8192', outputPath: 'font/' } } } ] }, plugins: [ // webpack 內置的 banner-plugin new webpack.BannerPlugin("Copyright by 765745342@qq.com"), // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + '/index.html' }), // 定義爲生產環境,編譯 React 時壓縮到最小 new webpack.DefinePlugin({ 'process.env': { 'NODE_ENV': JSON.stringify(process.env.NODE_ENV) } }), // 爲組件分配ID,經過這個插件webpack能夠分析和優先考慮使用最多的模塊,併爲它們分配最小的ID new webpack.optimize.OccurrenceOrderPlugin(), 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')) }), new OptimizeCssAssetsPlugin({ assetNameRegExp: /\.css$/g, cssProcessor: require('cssnano'), cssProcessorOptions: { discardComments: {removeAll: true } }, canPrint: true }) ] }
有些地方和 webpack.config.js
的配置是同樣的我就不作說明了。
extract-text-webpack-plugin
: 開發環境下,css 代碼是放在整個打包出來的那個 bundle.js 文件中的,發佈環境下固然不能混淆在一塊兒。該插件的主要是爲了抽離css樣式,防止將樣式打包在js中引發頁面樣式加載錯亂的現象。詳細介紹https://www.npmjs.com/package...
webpack.optimize.CommonsChunkPlugin
: 將第三方依賴單獨打包。即將 node_modules 文件夾中的代碼打包爲 vendor.js 將咱們本身寫的業務代碼打包爲 app.js。這樣有助於緩存,由於在項目維護過程當中,第三方依賴不常常變化,而業務代碼會常常變化。詳細介紹https://doc.webpack-china.org...
webpack.optimize.UglifyJsPlugin
: 壓縮你的JS代碼。詳細介紹https://doc.webpack-china.org...
optimize-css-assets-webpack-plugin
: CSS代碼壓縮。詳細介紹https://www.npmjs.com/package...
autoprefixer
: Autoprefixer是一個後處理程序,你能夠同Sass,Stylus或LESS等預處理器共通使用。它適用於普通的CSS,而你無需關心要爲哪些瀏覽器加前綴,只需全新關注於實現,並使用W3C最新的規範。詳細介紹https://www.npmjs.com/package...
這是一個自動給你加上css瀏覽器前綴,好比
你只需寫:
a { display: flex; }
這個插件自動給你添加廠商前綴:
a { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; }
這個插件請注意,你須要下載 postcss-loader
而且新建文件postcss.config.js
文件內容:
module.exports = { plugins: { 'autoprefixer': {browsers: 'last 5 version'} } }
這裏須要額外安裝的包:
postcss-loader
extract-text-webpack-plugin
optimize-css-assets-webpack-plugin
啓動項目
npm start
打包項目
npm run build