創建 package.json 文件
執行命令npm init
創建 package.json 文件,一步步輸入你自己的組件基本信息,下面是我創建的
{
"name": "react-code-previewer",
"version": "0.0.1",
"description": "基於 react 和 antd 的代碼預覽器組件",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/zhangwei900808/react-code-previewer.git"
},
"keywords": [
"react",
"antd",
"code-preview"
],
"author": "zhangwei",
"license": "MIT",
"bugs": {
"url": "https://github.com/zhangwei900808/react-code-previewer/issues"
},
"homepage": "https://github.com/zhangwei900808/react-code-previewer#readme"
}
初始化組件
首先在項目目錄下創建相應文件夾和基本配置文件,目錄結構如下所示:
|-- com.github
|-- .editorconfig
|-- .gitignore
|-- .npmignore
|-- LICENSE
|-- package.json
|-- .react-code-previewer
|-- components
| |-- index.js
| |-- code-previewer
| |-- index.js
| |-- style
| |-- index.js
| |-- index.scss
|-- src
創建好之後,我們開始製作該組件,在目錄 code-previewer/index.js 添加代碼,如下所示:
import React, { Component } from "react";
class CodePreviewer extends Component {
render() {
<div className="code-preview-container">
<div className="cp-component">
<div className="component-header">header</div>
<div className="component-content">content</div>
<div className="component-footer">footer</div>
</div>
<div className="cp-code">
<div className="code-header">code header</div>
<div className="code-tabs">code tabs</div>
<div className="code-content">code content</div>
</div>
</div>;
}
}
export default CodePreviewer;
在目錄 code-previewer/style/index.js 添加代碼,如下所示:
import "./index.scss";
在目錄 code-previewer/style/index.scss 添加代碼,如下所示:
.code-preview-container {
.cp-component {
.component-header {}
.component-content {}
.component-footer {}
}
.cp-code {
.code-header {}
.code-tabs {}
.code-content {}
}
}
我們現在已經初始化組件內容,雖然很簡單,後面我們再優化,現在我們要對外暴露該組件,所以我們在目錄 /components/index.js 添加代碼,如下:
import CodePreview from "./code-previewer";
export { CodePreview };
export default { CodePreview };
umd 打包
首先我們在目錄創建.react-code-preview/webpack.config.umd.js 文件,並添加如下代碼:
const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const nodeExternals = require("webpack-node-externals");
const WebpackMd5Hash = require("webpack-md5-hash");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const resolve = dir => path.join(__dirname, ".", dir);
const isProd = process.env.NODE_ENV === "production";
const { version, name, description } = require("../package.json");
const distDir = path.join(process.cwd(), "dist");
module.exports = {
mode: "production",
entry: { [name]: "./components/index.js" },
output: {
path: distDir,
filename: "[name].min.js",
// 採用通用模塊定義
libraryTarget: "umd",
library: name
},
devtool: "#source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
}
]
},
resolve: {
enforceExtension: false,
extensions: [".js", ".jsx", ".json", ".less", ".css"]
},
// 注意:本地預覽的時候要註釋,否則報 require undefined
// https://stackoverflow.com/questions/45818937/webpack-uncaught-referenceerror-require-is-not-defined
externals: [nodeExternals()],
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [distDir]
}),
new MiniCssExtractPlugin({
filename: "[name].css"
}),
new WebpackMd5Hash(),
new webpack.BannerPlugin(` \n ${name} v${version} \n ${description} ${fs.readFileSync(path.join(process.cwd(), "LICENSE"))}`)
],
//壓縮js
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: "styles",
test: /\.scss$/,
chunks: "all",
enforce: true
}
}
},
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css\.*(?!.*map)/g, //注意不要寫成 /\.css$/g
cssProcessor: require("cssnano"),
cssProcessorOptions: {
discardComments: { removeAll: true },
safe: true,
autoprefixer: false
},
canPrint: true
})
]
},
node: {
setImmediate: false,
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty"
}
};
在目錄根目錄下創建 .babelrc 文件,並添加如下代碼:
{
"presets": [
["@babel/preset-env", {
"modules": false,
}], "@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"useESModules": false
}]
]
}
創建完成之後添加依賴包,並修改 package.json 文件,如下:
"scripts": {
"build:umd": "webpack --mode production --config .react-code-previewer/webpack.config.umd.js"
},
"devDependencies": {
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"@babel/plugin-transform-runtime": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.5.5",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"fs": "^0.0.1-security",
"mini-css-extract-plugin": "^0.8.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"path": "^0.12.7",
"react": "^16.9.0",
"sass-loader": "^7.2.0",
"style-loader": "^1.0.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.39.2",
"webpack-cli": "^3.3.6",
"webpack-node-externals": "^1.7.2"
}
添加完成之後,執行命令打包
yarn build:umd
成功在 dist 目錄下創建好了打包後的.js文件,目錄如下所示:
|-- com.github
|-- .babelrc
|-- .editorconfig
|-- .gitignore
|-- .npmignore
|-- LICENSE
|-- directoryList.md
|-- package.json
|-- yarn.lock
|-- .react-code-previewer
| |-- webpack.config.umd.js
|-- components
| |-- index.js
| |-- code-previewer
| |-- index.js
| |-- style
| |-- index.js
| |-- index.scss
|-- dist
| |-- react-code-previewer.min.js
| |-- react-code-previewer.min.js.map
|-- src
注意:因爲後面組件會使用 bable-plugins-import 按需加載組件,所以上面的組件並沒有直接引用.scss文件,這樣也就不會在 dist 文件夾下打包.css文件了,但是.css 文件一定要有,後面會講gulp如何打包.css文件
commonjs 打包
上面講了如何使用webpack.config.umd.js 的 umd 模式打包 react 組件,接下來我們講如何使用 commonjs 模式打包 react 組件,commonjs 模式打包我們使用的是 babel 直接打包,並且要修改.babelrc 和 package.json,如下:
.babelrc
{
"presets": [
["@babel/env", {
"loose": true,
"modules": "cjs"
}], "@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"useESModules": false
}],
]
}
package.json
"build:commonjs": "babel components -d lib --source-maps"
添加完成之後,執行命令打包
yarn build:commonjs
|-- com.github
|-- .babelrc
|-- .editorconfig
|-- .gitignore
|-- .npmignore
|-- LICENSE
|-- directoryList.md
|-- package.json
|-- yarn.lock
|-- .react-code-previewer
| |-- webpack.config.umd.js
|-- components
| |-- index.js
| |-- code-previewer
| |-- index.js
| |-- style
| |-- index.js
| |-- index.scss
|-- dist
| |-- react-code-previewer.min.js
| |-- react-code-previewer.min.js.map
|-- lib
| |-- index.js
| |-- index.js.map
| |-- code-previewer
| |-- index.js
| |-- index.js.map
| |-- style
| |-- index.js
| |-- index.js.map
|-- src
es modules 打包
es modules打包和 babel 打包很類似也是通過 babel 打包,不同的是.babelrc 文件有所修改,代碼如下:
.babelrc
{
"presets": [
["@babel/env", {
"loose": true,
"modules": false
}], "@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"useESModules": true
}]
]
}
package.json
"build:es": "babel components -d es --source-maps"
添加完成之後,執行命令打包
yarn build:es
![clipboard.png](/img/bVbwtk0)
![clipboard.png](/img/bVbwtlf)
|-- react-code-previewer
|-- .babelrc
|-- .editorconfig
|-- .gitignore
|-- .npmignore
|-- LICENSE
|-- package.json
|-- yarn.lock
|-- .react-code-previewer
| |-- webpack.config.umd.js
|-- components
| |-- index.js
| |-- code-previewer
| |-- index.js
| |-- style
| |-- index.js
| |-- index.scss
|-- dist
| |-- react-code-previewer.min.js
| |-- react-code-previewer.min.js.map
|-- es
| |-- index.js
| |-- index.js.map
| |-- code-previewer
| |-- index.js
| |-- index.js.map
| |-- style
| |-- index.js
| |-- index.js.map
|-- lib
| |-- index.js
| |-- index.js.map
| |-- code-previewer
| |-- index.js
| |-- index.js.map
| |-- style
| |-- index.js
| |-- index.js.map
|-- src
這樣就完成了 umd、commonjs 和 es 的三種打包方式,但是這樣有個問題:每次打包都要修改.babelrc 文件,能不能直接通過一條命令打包三種模式的方法呢?下面我們就來講講。
## 組合三種打包模式
通過三種打包模式我們發現,.babelrc 文件跟三種模式打包有關,尤其是其中幾個對象的設置,如:loose、modules 和 useESModules,其它的設置都一樣,所以我們可以使用cross-env BABEL_ENV=umd(commonjs 或者 es)增加 BABEL_ENV 環境變量進行判斷。還有,.babelrc 文件我們要換成.babelrc.js,因爲前者不能使用 js 語法,這裏[有篇文章](https://www.babeljs.cn/docs/configuration)很好的分析.babelrc、.babelrc.js 和 babel.config.js文件之間的區別
## gulp 打包 css
## 組件按需加載
## 發佈組件到 npm
## 發佈組件到 github pages
## 使用組件
## 總結
1、js sourcemap
2、css sourcemap