React項目的初始化、webpack的安裝、如何使用jsx和less。
一、初始 React 項目
react項目的初始化比較簡單,我用的就是react的腳手架。三種方式:
1、NPM
npm init react-app my-app
2、NPX
npx create-react-app my-app
3、Yarn
yarn create react-app my-app
my-app 是項目的名字,運行命令時會在當前目錄下自動創建一個名字叫作 my-app 的項目文件夾。命令運行完畢,簡單的React項目就初始化完成了。項目的初始的代碼結構式這個樣子的:
進入項目文件,你可以通過 npm run start 來運行項目,會跳出一個React的歡迎頁
my-app ├── README.md ├── node_modules ├── package.json ├── .gitignore ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg └── serviceWorker.js
二、Webpack安裝程序
Webpack
WebPack可以看做是模塊打包機:它會分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(less、jsx、Scss、TypeScript等),並將其打包為合適的格式以供瀏覽器使用。
為什么要用 WebPack ?
1、模塊化
在webpack看來一切都是模塊!這就是它不可不說的優點,包括你的JavaScript代碼,也包括CSS和fonts以及圖片等等等,只有通過合適的loaders,它們都可以被當做模塊被處理。
2、預處理(Less,Sass,ES6,TypeScript……)
3、主流框架腳手架支持(Vue,React,Angular)
4、龐大的社區(資源豐富,降低學習成本)
1、開始安裝Webpack
使用 webpack 首先你需要安裝 webpack-dev-server 在本地環境中為捆綁的應用程序提供服務、webpack-cli 在配置文件中來配置你的Webpack 設置。
npm install --save-dev webpack webpack-dev-server webpack-cli
2、修改 package.json
主要修改 package.json 中的啟動項
"scripts": { "start": "webpack-dev-server --config config/webpack.base.config.js --mode development", ... }
腳本將 webpack-dev-server 與名為 webpack.base.config.js 一起使用。我在項目的根目錄下創建了一個 config 文件夾,里面用來存放 webpack 的配置文件。The --mode development
flag just adds default Webpack configurations which came with Webpack 4.
3、編輯 webpack.base.config.js
module.exports = { entry: './src/index.js', output: { path: __dirname + '/public', publicPath: '/', filename: 'bundle.js' }, devServer: { contentBase: './public' } };
文件說明:
(1) 我們希望使用 “./src/index.js” 文件作為入口點。
(2) 綁定的文件最后生成的js文件,叫做: bundle.js .
(3)生成的位置在:“/public”
4、修改一下public/index.html 和 src/index.js 中的內容
因為我們初步使用 webpack 來啟動我們的項目,所以像是 svg圖片、react的識別都還沒有配置。所以先將這兩個文件進行修改,這些修改不會影響到之后咱們的搭建。將兩個文件修改成下面的樣子。
public/index.html
<!DOCTYPE html> <html lang="en"> <head> <title>React App</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <base href="/"> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <script src="./bundle.js"></script> </body> </html>
src/index.js
console.log('My Minimal React Webpack Babel Setup');
5、npm start
OK,我們已經使用 webpack 將項目的啟動腳本配置好了。下面就是使用 npm start 來驗證我們的啟動命令是否成功。
項目啟動成功,接下來訪問地址 localhost:8080 來訪問一下。
其中我們在 src/index.js 里面 console.log 的信息已經顯示在了瀏覽器里邊,說明 index.js 已經通過 webpack 編譯成了 bundle.js。
三、配置 babel
babel 是一個廣泛的轉碼器,可以將 ES6 代碼轉化為 ES5 代碼。從而在現有的環境中執行。
1、安裝插件
在項目根目錄下指定下面命令,作用是使得 babel 正常執行:
npm install --save-dev @babel/core @babel/preset-env
為了將它連接到Webpack,還需要安裝一個加載器:
npm install --save-dev babel-loader
還需要一個配置,來將 React 的 jsx 語法轉化成 JavaScript:
npm install --save-dev @babel/preset-react
2、編輯 webpack.base.config.js 文件
在 webpack.base.config.js 文件中添加代碼:
module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ['babel-loader', 'eslint-loader'] }, { test: /\.(css|less)$/, use:["style-loader", "css-loader", "less-loader"] }, { test: /\.svg$/, use: ['file-loader'] } ] }, resolve: { extensions: ['*', '.js', '.jsx', '.css', '.less'] }
這些代碼的作用是 是代碼識別 js、jsx、css、less、svg圖片文件的。
這里要下載幾個 loader 和 plugin:
npm install --save-dev style-loader css-loader less less-loader eslint-loader file-loader extract-text-webpack-plugin@next
在項目根目錄下創建 .babelrc
文件
.babelrc
{ "presets": [ "@babel/preset-env", "@babel/preset-react" ] }
3、修改 src/index.js 文件
webpack 已經認less和css文件了。現在我們修改一下index.js
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; ReactDOM.render(<App />, document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: http://bit.ly/CRA-PWA serviceWorker.unregister();
然后將 App.css 改名為 App.less, 內容不需要改,如下圖:
OK,現在執行命令 npm start,訪問 localhost:8080 看一下結果.
成功。
四、使用 webpack 打包項目
1、首先我在 config 文件夾中創建 path.js、webpack.opt.config.js、 webpack.prod.config.js 三個文件
path.js
path 的作用是 提供path路徑的,自定義的path。
var path = require('path'); var fs = require('fs'); // Make sure any symlinks in the project folder are resolved: // https://github.com/facebookincubator/create-react-app/issues/637 var appDirectory = fs.realpathSync(process.cwd()); function resolveApp(relativePath) { return path.resolve(appDirectory, relativePath); } // We support resolving modules according to `NODE_PATH`. // This lets you use absolute paths in imports inside large monorepos: // https://github.com/facebookincubator/create-react-app/issues/253. // It works similar to `NODE_PATH` in Node itself: // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders // We will export `nodePaths` as an array of absolute paths. // It will then be used by Webpack configs. // Jest doesn't need this because it already handles `NODE_PATH` out of the box. // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 var nodePaths = (process.env.NODE_PATH || '') .split(process.platform === 'win32' ? ';' : ':') .filter(Boolean) .filter(folder => !path.isAbsolute(folder)) .map(resolveApp); // config after eject: we're in ./config/ module.exports = { appBuild: resolveApp('build'), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveApp('src/index.js'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), yarnLockFile: resolveApp('yarn.lock'), appNodeModules: resolveApp('node_modules'), nodePaths: nodePaths };
webpack.opt.config.js
webpack.opt.config.js 是在打包時做 css代碼 優化的
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); module.exports = { optimization: { minimizer: [ new UglifyJsPlugin({ uglifyOptions: { mangle: { keep_fnames: true, }, }, }) ], }, plugins: [ new OptimizeCssAssetsPlugin() ], }
webpack.prod.config.js
webpack.prod.config.js 用來將各個 config 文件融合到一起
var webpack = require('webpack');
var merge = require('webpack-merge');
var baseConfig = require('./webpack.base.config');
var optimizationConfig = require('./webpack.opt.config');
const productionConfiguration = function (env) {
const NODE_ENV = env.NODE_ENV ? env.NODE_ENV : 'development';
return {
plugins: [
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) }),
]
};
}
module.exports = merge.smart(baseConfig, optimizationConfig, productionConfiguration);
安裝 uglifyjs-webpack-plugin 和 webpack-merge :
npm install --save-dev uglifyjs-webpack-plugin
npm install --save-dev webpack-merge
2、在項目根目錄下創建 server 文件夾
server 的作用是,打包成功之后,項目啟動一個server。可以通過訪問 server 地址來直接訪問項目build之后生成的包。
server/index.js
const express = require('express'); const path = require('path'); const http = require('http'); const app = express(); // Point static path to dist app.use(express.static(path.join(__dirname, '..', 'build'))); const routes = require('./routes') app.use('/', routes); /** Get port from environment and store in Express. */ const port = process.env.PORT || '3000'; app.set('port', port); /** Create HTTP server. */ const server = http.createServer(app); /** Listen on provided port, on all network interfaces. */ server.listen(port, () => console.log(`Server Running on port ${port}`))
routes/index.js
const path = require('path'); const router = require('express').Router(); router .get('/*', (req, res, next) => { const routePath = path.join(__dirname + '..', '..', '..','build/' + 'index.html'); res.sendFile(routePath); }) module.exports = router;
這里面要安裝一個 express:
npm install --save-dev express
3、修改 webpack.base.config.js
webpack.base.config.js 最終版
const webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var paths = require('./paths');
module.exports = {
entry: './src/index.js',
output: {
path: paths.appBuild,
publicPath: '/',
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
},
{
test: /\.(css|less)$/,
use:["style-loader", "css-loader", "less-loader"]
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: "css-loader!less-loader",
// })
},
{
test: /\.svg$/,
use: ['file-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: './index.html'
}),
new ExtractTextPlugin('style.css')
],
resolve: {
extensions: ['*', '.js', '.jsx', '.css', '.less']
},
devServer: {
contentBase: './public',
hot: true
}
};
標紅的部分是兩種 css 的 load 方式。
直接使用 " use: [] " : 打包時,css會被打包到 bundle.js 里面。
使用 " use: ExtractTextPlugin.extract() " : 和 plugin 中的 new ExtractTextPlugin('style.css') 聯用。打包時會將css文件分離開來進行打包,在 build 文件夾中生成一個 style.css 文件.
安裝 html-webpack-plugin:
npm install --save-dev html-webpack-plugin
4、package.json
將 script 中的 build 換成如下語句:
"prestart:prod": "webpack --mode production --config config/webpack.prod.config.js --env.NODE_ENV=production --progress", "start:prod": "node server",
5、測試
OK,全部配置完畢了,下面我們來測試一下是否成功。
運行命令 npm run start:prod
build 生成的文件,三個如下:
運行成功,訪問 localhost:3000 訪問 build 好的包。
執行命令: npm start
訪問 localhost:8080: