npm 註冊登入
- 前置條件: 切到對應的npm源
npm logout
npm login
依次輸入賬號、密碼、郵箱
npm publish (會提示去npm官網驗證郵箱地址)
- npm 釋出時可能遇到的問題
- 源出錯
- 包名重複
- 每次釋出前要修改
package.json
的版本號,必須要大於上一次的版本號
- npm link 本地除錯:為除錯帶來的頻繁發包,可以使用 npm link 將npm包代理到本地除錯,操作步驟:
- 進入原始碼目錄執行
npm link
- 進入使用目錄即示例程式碼執行
npm link [包名]
,折後就可以直接在示例程式碼處使用import xxx from 'xxx'
進行除錯了
- 進入原始碼目錄執行
webpack ts babel 等打包配置檔案書寫
參照這篇文章寫的挺全面的,只不過它沒有引入
typescript
- 本文寫時
"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" ] } 複製程式碼
- .babelrc
{ "presets": [ "@babel/preset-env", "@babel/preset-react", ], "plugins": [ "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread" ] } 複製程式碼
- .postcss.config.js
// postcss 配置參考 https://segmentfault.com/a/1190000008030425 module.exports = { plugins: [ require('autoprefixer')({ /* ...options */ }) ] } 複製程式碼
- webpack.base.js
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"] } }; 複製程式碼
- webpack.dev.config.js
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); 複製程式碼
- webpack.prod.config.js
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 } 複製程式碼
- 完成以上步驟
ts 和 babel
上述配置使用的
babel ts
的工作方式為tsx -(ts-loader) -> es6 -(babel-loader) -> es5
即本專案的ts-loader
分支
- 我這個專案的 master分支並沒有使用上述文章介紹的幾種方式,我是直接使用 tsc 編譯器(利用tsconfig.json配置),將原始碼tsx直接編譯成es5,即只用 ts-loader 處理 ts、tsx,tsconfig.json 的target設定成es5,引入之後執行良好,暫未發現異常
ts 與 babel幾種協同工作方式
-
主要參考這幾篇Webpack 轉譯 Typescript 現有方案
-
綜上所述,大致有以下兩種方案
- ts-loader + babel-loader
`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 指令碼·
複製程式碼
上述不管每種方法最終的結果都是隻轉換高版本ES的語法或者將TypeScript轉換為ES5語法,但並不轉換api
- 語法:let、const、class、Decorator
- api:includes、Object.assign、Array.from、Promise、async await
- 語法靠
@babel/preset-env
的相關配置進行轉義 - api靠
@babel/polyfill
或@babel/runtime
和@babel/plugin-transform-runtime
- update:tsc 編譯器好像可以帶上polyfill、知乎提問/ts-polyfill
有個疑問我現在也沒有明確答案?
像我們寫的這些 npm包或ui元件庫,需不需要自己做 polyfill? 還是交給使用方即宿主環境做 我看了 `antd-mobile` 打包後的檔案,發現像 `Promise, Object.assign`並沒有做polyfill 複製程式碼
babel相關-@babel/polyfill、@babel/preset-env、@babel/plugin-transform-runtime
- 參考文章
- Babel學習系列1-Babel歷史
- Babel學習系列2-Babel設計,組成
- Babel學習系列3-babel-preset,babel-plugin
- Babel學習系列4-polyfill和runtime差別(必看)
- Babel 編譯出來還是 ES 6?難道只能上 polyfill?
- 這個網站,可以讓你停止“瞎配”前端工具鏈
- www.tangshuang.net/7427.html
- 動態polyfill方案主要是依據
@babel/preset-env
的useBuiltIn
確定的 @babel/babel-polyfill
整個應用全域性引入,模擬完整的ES6+環境@babel/babel-runtime @babel/babel-plugin-transform-runtime
開發像vue這樣的框架、庫,提供一個沙盒環境不會汙染原型鏈,後者主要為前者提供引用幫助,減少程式碼體積