Как упаковать компонент React для распространения через NPM
Я написал компонент React, транслировал его с помощью Babel, собирал и собирал с помощью Webpack. Я хотел использовать его в другом приложении через NPM. Мой пакет публикации NPM должен включать поведение компонентов, стили и изображения. Итак, насколько сложно упаковать мой компонент React для распространения через NPM? Может быть, час или около того работы, не так ли?
Что ж, мне потребовалось намного больше времени, чтобы понять это из-за следующих ударов скорости.
- Конфликт версий React
- Как связать и использовать стили из компонента
- Как включить и объединить изображения
Вот шаги.
1. СДЕЛАЙТЕ ПУБЛИКАЦИЮ ПАКЕТА NPM
npm init
В package.json убедитесь, что эти поля заполнены:
package.json{ "name": "myUnflappableComponent", "version": "0.0.29", "main": "dist/index.js", "publishConfig": { "access": "restricted" }, ... }
2. НЕ РЕАГИРОВАТЬ. ИСПОЛЬЗУЙТЕ REACT И REACT-DOM РОДИТЕЛЯ.
В package.json добавьте React и react-dom в peerDependencies проекта (и удалите его из dependencies, но добавьте в devDependencies для разработки)
...
"peerDependencies": {
"react": ">=15.0.1",
"react-dom": ">=15.0.1"
},
"devDependencies": {
"react": ">=15.0.1",
"react-dom": ">=15.0.1"
},
...
В конфигурации вашего веб-пакета создайте пакет UMD
...
module.exports = {
...
output: {
path: path.join(__dirname, './dist'),
filename: 'myUnflappableComponent.js',
library: libraryName,
libraryTarget: 'umd',
publicPath: '/dist/',
umdNamedDefine: true
},
plugins: {...},
module: {...},
resolve: {...},
externals: {...}
}
И супер-пупер важно, не объединяйте React
module.exports = {
output: {...},
plugins: {...},
module: {...},
resolve: {
alias: {
'react': path.resolve(__dirname, './node_modules/react'),
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
}
},
externals: {
// Don't bundle react or react-dom
react: {
commonjs: "react",
commonjs2: "react",
amd: "React",
root: "React"
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "ReactDOM",
root: "ReactDOM"
}
}
}
3. УСТАНОВИТЕ ФАЙЛ .NPMIGNORE.
Если вы не настроили файл .npmignore, npm будет использовать ваш .gitignore файл, и могут случиться неприятности. Разрешен пустой .npmignore файл. Вот как выглядит мой:
webpack.local.config.js
webpack.production.config.js
.eslintrc
.gitignore
4. ДОБАВИТЬ СЦЕНАРИЙ ДЛЯ ПОДГОТОВКИ К ВАШЕМУ PACKAGE.JSON
Строить перед публикацией.
"scripts": {
"prepublish": "rm -rf ./dist && npm run build",
...
}
5. ИЗВЛЕЧЬТЕ СВОИ CSS-ФАЙЛЫ ДЛЯ ИСПОЛЬЗОВАНИЯ
Мы используем файлы SCSS для наших стилей. Они компилируются в css и извлекаются Webpack.
Установите следующее:
npm install --save-dev extract-text-webpack-plugin node-sass style-loader css-loader sass-loader
Обновите свой webpack.config
const ExtractTextPlugin = require('extract-text-webpack-plugin');module.exports = { ... plugins:[ new ExtractTextPlugin({ filename: 'myUnflappableComponent.css', }), ], module:{ rules:[ { test: /\.*css$/, use : ExtractTextPlugin.extract({ fallback : 'style-loader', use : [ 'css-loader', 'sass-loader' ] }) }, .... ] } }
6. ИЗОБРАЖЕНИЯ В CSS
То, как вы включаете изображения в свой компонент, будет определять, получит ли их потребитель вашего компонента.
Я включаю их в файл css, используя свойство содержимого. Например
.mySky{
width: 20px;
height: 20px;
content: url('../assets/images/thunderSky.png');
}
7. УБЕДИТЕСЬ, ЧТО ВАШИ ИЗОБРАЖЕНИЯ ДОСТУПНЫ ЗА ПРЕДЕЛАМИ КОМПОНЕНТА.
Проблема, с которой я столкнулся, заключалась в том, что относительные пути изображений в опубликованных файлах CSS были перепутаны. После долгих поисков помогла эта статья (также в ссылках ниже).
Установите следующее:
npm install --save-dev file-loader url-loader
Обновите свой webpack.config следующим образом:
module.exports = {
...
module: {
rules: [
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options:{
fallback: "file-loader",
name: "[name][md5:hash].[ext]",
outputPath: 'assets/',
publicPath: '/assets/'
}
}
]
},
...
resolve: {
alias:{
...
'assets': path.resolve(__dirname, 'assets')
}
}
]
}
}
ОБЪЯВЛЕНИЯ И ССЫЛКИ:
- Как опубликовать свой пакет на npm (все о
package.json) - Опубликовать бета-версию в NPM
- Экспорт изображений через webpack (
webpack.config.js) - Моя полная конфигурация веб-пакета:
const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const pkg = require('./package.json'); const path = require('path');const libraryName= pkg.name;module.exports = { entry: path.join(__dirname, "./src/index.js"), output: { path: path.join(__dirname, './dist'), filename: 'myUnflappableComponent.js', library: libraryName, libraryTarget: 'umd', publicPath: '/dist/', umdNamedDefine: true }, plugins: [ new ExtractTextPlugin({ filename: 'myUnflappableComponent.css', }), ], node: { net: 'empty', tls: 'empty', dns: 'empty' }, module: { rules : [ { test: /\.(png|svg|jpg|gif)$/, use: [ { loader: 'url-loader', options:{ fallback: "file-loader", name: "[name][md5:hash].[ext]", outputPath: 'assets/', publicPath: '/assets/' } } ] }, { test: /\.*css$/, use : ExtractTextPlugin.extract({ fallback : 'style-loader', use : [ 'css-loader', 'sass-loader' ] }) }, { test: /\.(js|jsx)$/, use: ["babel-loader"], include: path.resolve(__dirname, "src"), exclude: /node_modules/, }, { test: /\.(eot|ttf|woff|woff2)$/, use: ["file-loader"], }, { test: /\.(pdf|doc|zip)$/, use: ["file-loader"], }] }, resolve: { alias: { 'react': path.resolve(__dirname, './node_modules/react') , 'react-dom': path.resolve(__dirname, './node_modules/react-dom'), 'assets': path.resolve(__dirname, 'assets') } }, externals: { // Don't bundle react or react-dom react: { commonjs: "react", commonjs2: "react", amd: "React", root: "React" }, "react-dom": { commonjs: "react-dom", commonjs2: "react-dom", amd: "ReactDOM", root: "ReactDOM" } } };