npm logout
npm login
依次輸入帳號、密碼、郵箱
npm publish (會提示去npm官網驗證郵箱地址)
package.json
的版本號,必需要大於上一次的版本號npm link
npm link [包名]
,折後就能夠直接在示例代碼處使用 import xxx from 'xxx'
進行調試了參照這篇文章寫的挺全面的,只不過它沒有引入
typescript
css
"webpack": "^4.41.6",
,下面把主要流程記錄一下最終完成的目錄結構以下所示|____babelrc // babel 配置
|____config // webpack配置
├── webpack.base.js // 公共配置
├── webpack.dev.config.js // 開發環境配置
└── webpack.prod.config.js // 打包發佈環境配置
|____example // 開發環境調試目錄
|____node_modules
|____README.md
|____yarn.lock
|____public // 開發調試環境的模板 index.html
|____.gitignore
|____package.json
|____lib // 打包後目錄
|____tsconfig.json // ts配置
|____postcss.config.js // postcss配置
|____src // 組件源碼
|____.npmignore // 指定發佈 npm 的時候須要忽略的文件和文件夾
複製代碼
mkdir learnnpm & cd learnnpm & npm init
,根據提示依次填入信息,以後即生成 package.json
1. 由於使用webpack進行打包,安裝webpack相關依賴
主依賴: yarn add webpack webpack-cli webpack-dev-server webpack-merge -D
相關插件:clean-webpack-plugin html-webpack-plugin mini-css-extract-plugin
2. 安裝react相關
yarn add react react-dom
3. 安裝babel相關
yarn add @babel/cli @babel/core @babel/preset-env @babel/preset-react babel-loader @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread -D 4. 安裝 typescript ts-loader fork-ts-checker-webpack-plugin 5. 安裝css相關 style-loader css-loader postcss-loader less less-loader url-loader file-loader autoprefixer 複製代碼
package.json
.babelrc
webpack.config.js
postcss.config.js
相關內容以下{
// ...
"main": "lib/index.js", // 打包後的入口地址
"scripts": {
"start": "webpack-dev-server --config config/webpack.dev.config.js",
"build": "webpack --config config/webpack.prod.config.js",
"pub": "npm run build && npm publish" // 發佈 npm
},
// ...
"dependencies": {
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
"@types/react": "^16.9.19", // ts 須要用的相關庫types 文件
"@types/react-dom": "^16.9.5",
"@types/react-router-dom": "^5.1.3",
"autoprefixer": "^9.7.4",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.4.2",
"fork-ts-checker-webpack-plugin": "^0.5.2", // ts類型校驗webpack插件
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0", // 抽離css插件
"postcss-loader": "^3.0.0",
"style-loader": "^1.1.3",
"ts-loader": "^6.2.1",
"typescript": "^3.7.5",
"url-loader": "^3.0.0",
"webpack": "^4.41.6",
"webpack-cli": "3.3.7",
"webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2"
},
"browserslist": [ // postcss autoprefixer 用到的配置
"iOS >= 6",
"Android >= 4",
"IE >= 9"
]
}
複製代碼
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread"
]
}
複製代碼
// postcss 配置參考 https://segmentfault.com/a/1190000008030425
module.exports = {
plugins: [
require('autoprefixer')({ /* ...options */ })
]
}
複製代碼
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.(ts|tsx)$/,
use: [
"babel-loader",
{
loader: 'ts-loader',
options: {
// 關閉類型檢查,即只進行轉譯, 類型檢查交給 fork-ts-checker-webpack-plugin 在別的的線程中作
transpileOnly: true
}
}
],
exclude: /node_modules/
},
{
// .css/less 解析
test: /\.(less|css)$/,
use: [
'style-loader',
"css-loader",
"postcss-loader",
"less-loader"
],
},
{
// 圖片解析
test: /\.(png|jpg|gif)$/,
include: path.resolve(__dirname, "..", "src"),
use: ["url-loader?limit=8192&name=assets/image/[name].[hash:4].[ext]"]
},
{
// 文件、字體解析
test: /\.(eot|woff|svg|ttf|woff2|otf|appcache|mp3|mp4|pdf)(\?|$)/,
include: path.resolve(__dirname, "..", "src"),
use: ["file-loader?name=assets/font/[name].[hash:4].[ext]"]
},
]
},
resolve: {
//後綴名自動補全,引入時可沒必要寫後綴名
extensions: [".ts", ".tsx", ".js", ".jsx", ".less", ".css"]
}
};
複製代碼
const path = require('path');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const baseConfig = require('./webpack.base.js');
const devConfig = {
mode: 'development', // 開發模式
entry: path.join(__dirname, "../example/src/app.js"), // 項目入口,處理資源文件的依賴關係
output: {
path: path.join(__dirname, "../example/src/"),
filename: "bundle.js",
// 使用webpack-dev-sevrer啓動開發服務時,並不會實際在`src`目錄下生成bundle.js,打包好的文件是在內存中的,但並不影響咱們使用。
},
module: {
rules: []
},
plugins: [
new HtmlWebpackPlugin({
title: 'learn npm',
filename: "index.html",
template: "./public/index.html",
inject: true,
}),
],
devServer: {
contentBase: path.join(__dirname, '../example/src/'),
compress: true,
port: 3001, // 啓動端口爲 3001 的服務
// open: true // 自動打開瀏覽器
},
};
module.exports = merge(devConfig, baseConfig);
複製代碼
const path = require('path');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.js');
// const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 用於將組件的css打包成單獨的文件輸出到`lib`目錄中
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const prodConfig = {
mode: 'production',
entry: path.join(__dirname, "../src/index.tsx"),
output: {
path: path.join(__dirname, "../lib/"),
filename: "index.js",
libraryTarget: 'umd', // 採用通用模塊定義
libraryExport: 'default', // 兼容 ES6 的模塊系統、CommonJS 和 AMD 模塊規範
},
module: {
rules: [
// 我在打包的沒有作css抽離,故註釋了
// {
// test: /\.css$/,
// loader: [MiniCssExtractPlugin.loader, 'css-loader?modules'],
// },
]
},
plugins: [
// new MiniCssExtractPlugin({
// filename: "main.min.css" // 提取後的css的文件名
// }),
new CleanWebpackPlugin(),
],
externals: { // 定義外部依賴,避免把react和react-dom打包進去
react: {
root: "React",
commonjs2: "react",
commonjs: "react",
amd: "react",
},
"react-dom": {
root: "ReactDOM",
commonjs2: "react-dom",
commonjs: "react-dom",
amd: "react-dom",
}
},
};
module.exports = merge(prodConfig, baseConfig);
複製代碼
{
"compilerOptions": {
"target": "es6",
"experimentalDecorators": true,
"strictNullChecks": false,
"module": "ESNext",
"moduleResolution": "node",
"jsx": "react",
"noUnusedParameters": false,
"noUnusedLocals": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"noImplicitAny": false,
"noImplicitReturns": false,
"noFallthroughCasesInSwitch": false,
"alwaysStrict": false,
"strict": false,
"strictBindCallApply": false,
"strictPropertyInitialization": false,
"types": [
"react",
"react-dom",
"node"
],
// "baseUrl": "src",
// 此處至關於webpack alias
// "paths": {
// "src/*": [
// "*"
// ]
// }
},
"include": [
"src/"
],
"exclude": [
"node_modules",
"dist"
],
"compileOnSave": false
}
複製代碼
上述配置使用的
babel ts
的工做方式爲tsx -(ts-loader) -> es6 -(babel-loader) -> es5
即本項目的ts-loader
分支html
主要參考這幾篇Webpack 轉譯 Typescript 現有方案前端
綜上所述,大體有如下兩種方案vue
`ts-loader + tsc + tsconfig.json` 將 tsx 處理爲 es6
`babel-loader + babelrc` 接盤將 es6 按照 `@babel/presents-env` 處理爲 es5代碼
話外音: `ts-loader` 與 `new ForkTsCheckerWebpackPlugin` 配合 ==> webpack4以後`happypack`做用也小了,故不用了
如上文所配置
複製代碼
babel7 + @babel/preset-typescript
引入 @babel/preset-typescript,來處理 tsx 類型信息(其做用就是刪除ts類型信息)
webpack 配置 js、jsx、ts、tsx 都交由babel-loader 處理
另外在啓動一個 tsc 服務檢查代碼類型 tsc --watch (package.json npm 腳本·
複製代碼
@babel/preset-env
的相關配置進行轉義@babel/polyfill
或 @babel/runtime
和@babel/plugin-transform-runtime
有個疑問我如今也沒有明確答案?
像咱們寫的這些 npm包或ui組件庫,需不須要本身作 polyfill?
仍是交給使用方即宿主環境作
我看了 `antd-mobile` 打包後的文件,發現像 `Promise, Object.assign`並無作polyfill
複製代碼
@babel/preset-env
的 useBuiltIn
肯定的@babel/babel-polyfill
整個應用全局引入,模擬完整的ES6+環境@babel/babel-runtime @babel/babel-plugin-transform-runtime
開發像vue這樣的框架、庫,提供一個沙盒環境不會污染原型鏈,後者主要爲前者提供引用幫助,減小代碼體積