最近公司給公司裏架設了私有的npm倉庫,相應地也須要一個用來發布react組件用的腳手架,在這個過程當中又又又又複習了一下webpack,在這裏分享下腳手架搭建的過程。css
首先,咱們預期的腳手架具備以下功能html
腳手架的名字暫時取react-simple-component-boilerplate
。node
首先建立一個新目錄用於放咱們的文件:react
mkdir react-simple-component-boilerplate cd react-simple-component-boilerplate
使用npm命令建立一個項目webpack
npm init
接下來會提示你輸入項目的名稱、版本號、做者等,也能夠一路回車,稍後修改。
這一步完成後,你的項目文件夾裏應該有一個package.json
文件了,這個文件保存了咱們項目和組件的各類信息。es6
接下來建立以下的目錄結構web
react-simple-component-boilerplate |-- config // webpack配置 |-- demo // 開發時預覽用 |-- dist // 打包結果 |-- src // 源文件目錄 | -- assets // 存放圖片等媒體文件 | -- style // 存放樣式,項目使用的是less來編寫樣式
既然咱們要發佈的是react組件,那依賴裏確定少不了react。
使用npm install
安裝下面的依賴npm
npm install react react-dom --save
打包工具選擇的是webpack,下面是開發依賴,也須要一併安裝json
"devDependencies": { // babel用於將你寫的es6+的代碼轉換到es5 "@babel/cli": "^7.0.0", "@babel/core": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", // 用於支持class屬性 "@babel/plugin-proposal-decorators": "^7.0.0", // 支持decorator "@babel/plugin-transform-modules-commonjs": "^7.0.0", "@babel/plugin-transform-runtime": "^7.0.0", // 自動polyfill es5不支持的api特性 "@babel/preset-env": "^7.0.0", // 根據目標環境來按需轉碼 "@babel/preset-react": "^7.0.0", // 讓babel支持react語法 "babel-loader": "^8.0.0", "css-loader": "^1.0.0", "file-loader": "^2.0.0", "html-loader": "^0.4.4", "less-loader": "^4.1.0", // 使用less來編寫樣式 "mini-css-extract-plugin": "^0.5.0", // 將css提取成一個單獨的文件 "style-loader": "^0.23.0", "webpack": "^4.26.0", "webpack-cli": "^3.1.2", // webpack4以後須要額外安裝webpack-cli "webpack-dev-server": "^3.1.14", // 開發時預覽組件所用的服務,在文件變化時會自動刷新頁面 "webpack-merge": "^4.1.4" // 用於合併webpack配置 },
在/src
目錄下新建一個index.js
,這就是咱們組件的入口文件了。
若是項目中要使用圖片、css等,分類放到assets
、style
文件夾下就好。gulp
下面咱們就在index.js中寫一個簡單的組件
/* src/index.js */ import React from 'react'; import './style/style.less'; // 使用less的狀況 import testPng from './assets/test.png'; // 使用圖片的狀況 export default class MyComponent extends Component { render(){ return (<div>A new Component</div>) } }
接下來,咱們在/demo
目錄下新建index.html
和demo.js
這兩個文件用於在開發組件時預覽組件效果。index.html
內容以下
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="root"></div> <script src="demo.bundle.js"></script> </body> </html>
在demo.js
中,咱們要使用一下剛剛寫的組件(位於/src/index.js
)看一下效果,開發中這個demo.js
文件會被打包成demo.bundle.js
,就是在上面index.html
中引用的js。
import React from 'react'; import ReactDom from 'react-dom'; import MyComponent from '../src/index' const Demo = () => { return <div> <h1>組件預覽:</h1> <MyComponent /> </div> } ReactDom.render(<Demo />, document.getElementById('root'));
4.1 配置webpack
在/config
下咱們創建三個webpack配置文件
因爲開發和發佈打包時webpack的配置有一部分是公共並且重複的,咱們把這部分的配置單獨拿出來放到webpack.base.js
中。
首先是公共配置webpack.base.js
:
module.exports = { module: { rules: [ { // 在webpack中使用babel須要babel-loader test: /\.js?$/, loader: 'babel-loader', exclude: '/node_modules/', }, { // 用於加載組件或者css中使用的圖片 test: /\.(jpg|jpeg|png|gif|cur|ico|svg)$/, use: [{ loader: 'file-loader', options: { name: "images/[name][hash:8].[ext]" } }] } ] } }
下面是開發時所用的webpack配置,寫在webpack.config.dev.js
中
const path = require('path'); const merge = require('webpack-merge'); const baseConfig = require('./webpack.base.js'); // 引用公共的配置 const devConfig = { entry: './demo/demo.js', // 入口文件 mode: 'development', // 打包爲開發模式 output: { filename: 'demo.bundle.js', // 輸出的文件名稱 path: path.resolve(__dirname, '../demo') // 輸出的文件目錄 }, devServer: { // 該字段用於配置webpack-dev-server contentBase: path.join(__dirname, '../demo'), compress: true, port: 9000, // 端口9000 open: true // 自動打開瀏覽器 }, module: { rules: [ { // 編譯less test: /\.less$/, exclude: '/node_modules/', use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'less-loader' }] }, ] }, } module.exports = merge(devConfig, baseConfig); // 將baseConfig和devConfig合併爲一個配置
須要注意的是,等會使用webpack-dev-sevrer啓動開發服務時,並不會實際在demo
文件夾下生成demo.bundle.js
,打包好的文件是在內存中的,但並不影響咱們使用。
下面是打包發佈時所用的webpack配置,寫在webpack.config.prod.js
中
const path = require('path'); const merge = require('webpack-merge'); const baseConfig = require('./webpack.base.js'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 用於將組件的css打包成單獨的文件輸出到`dist`目錄中 const devConfig = { entry: './src/index.js', mode: 'production', output: { path: path.resolve(__dirname, '../dist'), filename: 'index.js', // 輸出文件 libraryTarget: 'umd', // 採用通用模塊定義, 注意webpack到4.0爲止依然不提供輸出es module的方法,因此輸出的結果必須使用npm安裝到node_modules裏再用,否則會報錯 library: 'react-simple-component-boilerplate', // 庫名稱 libraryExport: 'default', // 兼容 ES6(ES2015) 的模塊系統、CommonJS 和 AMD 模塊規範 }, externals: { react: { root: "React", commonjs2: "react", commonjs: "react", amd: "react" }, "react-dom": { root: "ReactDOM", commonjs2: "react-dom", commonjs: "react-dom", amd: "react-dom" } }, module: { rules: [{ test: /\.(le|c)ss$/, use: [ MiniCssExtractPlugin.loader, "css-loader", { loader: "less-loader", options: { sourceMap: false } } ] } ] }, plugins: [ new MiniCssExtractPlugin({ filename: "main.min.css" // 提取後的css的文件名 }) ], } module.exports = merge(devConfig, baseConfig);
上面咱們配置了externals字段,這一點很是重要。
externals定義了外部依賴。將react和react-dom添加進該字段,說明咱們的組件將依賴外部的react和react-dom,這樣就能夠避免把react和react-dom打包進去(否則組件會很大)
4.1 配置babel
咱們須要用babel把咱們的代碼編譯成es5版本。在項目根目錄新建一個.babelrc
文件,輸入如下內容。
{ "presets": [ [ "@babel/preset-env", { "targets": "> 0.25%, not dead" } ], "@babel/preset-react" ], "plugins": [ "@babel/plugin-transform-runtime", "@babel/plugin-transform-modules-commonjs", [ "@babel/plugin-proposal-decorators", { "legacy": true } ], "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread" ] }
咱們在presets
其中使用了preset-env
, 規定了輸出的代碼目標環境是份額大於0.25%的瀏覽器。另外因爲咱們的項目裏使用了react
,presets
中就要加入preset-react
。
同時,plugins
配置了一些babel插件,用於支持裝飾器展開操做符等類內直接定義屬性等新的es特性。
4.3 配置啓動命令
咱們再次回到項目根目錄下的package.json
中,編輯以下
"scripts": { "build": "set NODE_ENV=production && webpack --config ./config/webpack.config.prod.js", "pub": "npm run build && npm publish", "dev": "webpack-dev-server --config ./config/webpack.config.dev.js" }, "main": "dist/index.js", "files": ["dist"]
build
命令用於打包組件dev
命令會使用webpack-dev-server
啓動一個開發服務用於預覽組件效果pub
命令進行打包組件而且發佈到npm上main
字段指定了咱們的組件的入口文件,files
字段用於指定咱們的npm包的文件目錄。
要發佈一個npm包,咱們需使用以下命令添加一個npm的帳號,若是已經添加過的這一步能夠跳過。
npm adduser
若是已經有npm帳號,可使用npm login
登錄。
若是不知道本身是否已經添加過了npm帳號,使用npm whoami
查看登錄信息便可
接下來就編輯package.json
把組件的名稱/版本/介紹等字段都填寫一下。
好了,接下咱們先使用npm run dev
命令,此時會自動打開默認瀏覽器預覽組件。
若是沒什麼問題的話,接下來使用npm run pub
進行打包和發佈。
等待發布完成後,咱們就下載安裝一下。
npm i your-component // 假設你的包名字叫your-component
使用本身發佈的組件
import YourComponent from 'your-component'; import 'your-component/dist/main.min.css'; // 若是給組件寫了樣式,須要手動導入css文件
到這裏,一個很是很是簡單的用於發佈react小組件的腳手架就搭好了,總結一下其中要注意的地方:
libraryTarget
要使用umd