歡迎加入qq羣:36952712
javascript若是隻是想試試 React,那麼建議使用 create-react-app來建立一個react項目。快速開始
由於 create-react-app 和 vue-cli 不同,create-react-app將webpack的相關配置直接封裝好了,因此自定製化程度不高,因此考慮手動構建一個 React項目css代碼下載html
準備工做
- 安裝node環境。
- 配置cnpm(看我的需求)。
- 準備一個空的文件夾react-demo。
初始化工程
從這裏開始新建一個react工程vue
1. 初始化工程目錄
1 cd react-demo 2 npm init
一路回車,咱們將獲得一個最簡單的npm目錄,會包含一個package.json。java
// package.json { "name": "react-demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
而後在react-demo目錄下新建一個程序的主目錄" src " 目錄。mddir src
node
2. 配置工程
1. webpack初體驗
首先安裝webpack和webpack-cli。 webpack4.Xreact
npm install --save-dev webpack webpack-cli -g
Q:--save-dev 和 --save的區別
A:--save-dev是你開發時候依賴的東西,--save是你發佈以後依賴的東西。區別
TIPS: -g表示全局安裝,--save-dev 能夠簡寫爲 -D ,--save 能夠簡寫爲 -S ,npm install 能夠簡寫爲 npm iwebpack
新建並配置webpack
新建webpack.config.js 文件。首先要理解webpack的幾個基礎概念入口(entry)、出口(output)、載入器(loader)、插件(plugins)、模式(mode) 。webpack中文文檔。代碼以下:git
1 // __dirname是node.js中的一個全局變量,它指向當前執行腳本所在的目錄 2 // path是node.js中提供的處理文件路徑的小工具。 (http://www.runoob.com/nodejs/nodejs-path-module.html) 3 const path = require('path'); 4 module.exports = { 5 // 項目入口,webpack今後處開始構建 6 entry: { 7 main: path.join(__dirname, 'src/index.js'), // 指定入口,能夠指定多個。參考webpack文檔 8 }, 9 output: { 10 path: path.join(__dirname, "dist"), // bundle生成(emit)到哪裏 11 filename: "bundle.js", // bundle生成文件的名稱 12 }, 13 }
- 這樣就完成了最簡單的webpack配置文件。相應的咱們須要在src目錄下新建一個index.js 文件。
- 接下來在命令行輸入
webpack --config ./webpack.config.js
就能夠輸出dist文件夾。 - 爲了方便起見,一般咱們會在package.json裏配置腳本命令。在scripts標籤下,添加一句
"build": "webpack --config ./webpack.config.js"
這樣,咱們就能夠經過npm run build
完成webpack打包。
配置開發應用服務器
正常狀況下,咱們須要以應用服務器打開咱們的網頁,webpack-dev-server提供了一個簡單的web服務器,而且可以實時從新加載。指南 首先須要安裝webpack-dev-server npm install -D webpack-dev-server
。
接下來,修改配置文件,告訴開發服務器,在哪裏尋找文件:github
1 // webpack.config.js 2 module.exports = { 3 devServer: { 4 contentBase: './dist' 5 } 6 }
這段配置告訴webpack-dev-server,在默認host和port下創建服務,並將contentBase目錄下的目錄,做爲可訪問文件。
接下來讓咱們的服務器跑起來,在package.json配置以下的命令腳本:
1 "scripts" : { 2 "start": "webpack-dev-server --mode development --open", 3 "build: "webpack --mode production --config ./webpack.config.js" 4 }
其中mode是上文中提到模式概念,webpack會有相應的內置優化。
Babel & React
ES6已經極爲流行了,不過目前仍有瀏覽器不兼容。同時react的jsx語法,也須要babel來將其轉化爲能兼容的js代碼。
1 npm install react react-dom react-router-dom -S 2 npm install babel-core babel-loader babel-preset-env babel-preset-react -D
安裝完以後,咱們須要在webpack中配置使其生效。在webpack.config.js 的module中添加rules規則,以下:
module.exports = { // ...省略 module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, enforce: 'pre', use: [{ loader: 'babel-loader', }, { loader: 'eslint-loader', // 指定啓用eslint-loader options: { formatter: require('eslint-friendly-formatter'), emitWarning: false } }] }, ] }
使用babel-loader咱們須要配置相應的規則,咱們能夠這樣配置:
同時考慮到,後期可能會別的規則需求,例如使用antDesign的按需引入,咱們將babel的配置提出來,在根目錄下新建文件 .babelrc
,並書寫如下代碼。
{ "presets": ["env","react"], // antd按需引入 // "plugins": ["react-hot-loader/babel", ["import", { "libraryName": "antd", "libraryDirectory": "es","style": "css" }], "transform-runtime"] }
到這裏,咱們就完成babel的相關配置,而且安裝了react相關依賴,能夠書寫jsx語法了。
關於樣式
前置安裝less-loader/scss-loader、style-loader、css-loader、postcss-loader。
- less-loader是將less編譯成css的loader
- postcss是將css加上瀏覽器Hack的loader
- css-loader用於在js中import、require等方法引入css
- style-loader用於將css最終寫入html文件。
test: /\.(css|less)$/, exclude: /node_modules/, include: /src/, use: [ {loader: "style-loader"}, { loader: 'css-loader', options: { minimize: process.env.NODE_ENV === 'production', importLoaders: 2, localIdentName: '[name]-[local]-[hash:base64:5]', modules:true } }, { loader: 'postcss-loader', options: { // 若是沒有options這個選項將會報錯 No PostCSS Config found plugins: (loader) => [ require('autoprefixer')(), //CSS瀏覽器兼容 ] } },{ loader: 'less-loader', options: { javascriptEnabled: true, } }],
其中test對應的能夠匹配的正則文件,include是須要編譯的目錄,exclude是跳過的目錄,use裏面能夠書寫跟loader相關的配置。
注意loader相關的順序,特別是使用ExtractTextWebpackPlugin將css文件單獨打包的時候,應注意從右往左的順序
至此,完成了一個簡單的react工程的配置。只包含有js和css相關的內容。
工程優化
關於單頁面工程的優化,有不少方向和方法。不論是生成環境構建仍是懶加載,亦或是構建性能。經過環境變量來實現不一樣的配置和打包策略。根據工程的需求和複雜度不一樣,會有不一樣的解決方案,而隨着如今頁面愈來愈複雜,各個組件又常常變更。暫時尚未真正的完美的解決方案。
在這裏,我只能作一些常規性的優化。
ExtractTextWebapckPlugin
在上面的配置中,咱們沒有單獨打包樣式文件,樣式文件會被打包在js裏面。如今經過ExtractTextWebpackPlugin單獨打包樣式文件。npm install -D extract-text-webapck-plugin
引入依賴,配置以下:
// module-> rules { test: /\.less$/, exclude: /node_modules/, include: /src/, // loader:['style-loader','css-loader'] use: ExtractTextWebapckPlugin.extract({ fallback:'style-loader', use: [ { loader: 'css-loader', options: { minimize: process.env.NODE_ENV === 'production', importLoaders: 2, localIdentName: '[name]-[local]-[hash:base64:5]', modules:true } }, { loader: 'postcss-loader', options: { // 若是沒有options這個選項將會報錯 No PostCSS Config found plugins: (loader) => [ require('autoprefixer')(), //CSS瀏覽器兼容 ] } },{ loader: 'less-loader', options: { javascriptEnabled: true, } }], } ) }, // plugins 下新增 new ExtractTextWebapckPlugin({ filename: 'css/[name]-[hash].css', // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, allChunks: true }),
爲打包後的文件增長hash
若是瀏覽器加載發現遠端文件沒有發生變化時,將會啓用緩存,致使新修改的頁面並無同步,這時候爲了不緩存,咱們就須要讓每次打包後的文件有不一樣的文件名,以減小緩存。
// webpack.config.js -> output output: { path: path.join(__dirname, "dist"), publicPath: '/', filename: "js/[name]-[hash]" + ".js", chunkFilename: "js/[name]-[hash]" + ".js", },
打包靜態文件
當頁面圖片較多時,會發送不少http請求,下降頁面性能。url-loader引入圖片編碼,生成dataURI,把圖片翻譯成一串字符串。再把字符串打包到文件中,最終只須要引入文件就能夠訪問圖片了。可是當圖片較大時,編碼會消耗性能。所以url-loader提供了一個limit參數,小於limit的文件會被轉爲dataURI,大於limit會使用file-loader傳入。首先引入依賴npm install -D file-loader url-loader
,配置以下:
// module->rules { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: 'static/img/[name].[hash:7].[ext]' } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: 'static/media/[name].[hash:7].[ext]' } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: 'static/fonts/[name].[hash:7].[ext]' } },
html-webpack-plugin
這是一個 webpack 插件,爲咱們在生成有 hash 標識符的 css,js時很是方便,它須要咱們指定一個模板,而後它會生成一個自動引入咱們生成的文件的新模板。
首先安裝依賴npm install -D html-webpack-plugin
,webpack配置以下:
const HtmlWebPackPlugin = require('html-webpack-plugin') // plugins下添加 new HtmlWebPackPlugin({ template: './src/index.html', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, filename: 'index.html' }),
devServer
開發服務器配置以下:
// webpack.config.js devServer: { // contentBase: path.join(__dirname, ""), contentBase: false, //since we use CopyWebpackPlugin. clientLogLevel: 'warning', publicPath: '/', hot: true, progress: true, overlay: { warnings: false, errors: true }, historyApiFallback: { rewrites: [ { from: /.*/, to: path.posix.join('/', 'index.html') }, ], }, // historyApiFallback: true, // quiet: true, // necessary for FriendlyErrorsPlugin compress: true, inline: true, port: 8083, host: '127.0.0.1', watchOptions: { poll: false, } },
由於配置了contentBase = false,因此使用CopyWebpackPlugin,仍是先安裝依賴npm install -D copy-webpack-plugin
,而後代碼以下:
// plugins // copy custom static assets new CopyWebpackPlugin([ { from: path.resolve(__dirname, './src/static'), to: 'static', ignore: ['.*'] } ]),
提取公共代碼
利用webpack4的splitChunks來分割代碼,配置以下:
// webpack.config.js //4.0配置 optimization: { /*splitChunks: { chunks: 'all',//"initial" | "async" | "all" cacheGroups: { default: false, vendors: false, }, },*/ /*splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: "vendor", chunks: "all" } } }*/ runtimeChunk: { name: "manifest" }, splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: "vendor", chunks: "all" } } } },