Skip to content

Instantly share code, notes, and snippets.

@christiangenco
Forked from PicchiKevin/migrate.sh
Last active May 15, 2024 17:06
Show Gist options
  • Save christiangenco/470a99f4823ee81f2b22bad83119f599 to your computer and use it in GitHub Desktop.
Save christiangenco/470a99f4823ee81f2b22bad83119f599 to your computer and use it in GitHub Desktop.
Heroicons v1 to v2

Heroicons v1 to v2 migration script

This script:

  1. Upgrades your heroicons library to the latest version (detecting if you're using heroicons/react or heroicons/vue and yarn or npm)
  2. Upgrades your import statements (from @heroicons/${framework}/{solid|outline} to @heroicons/${framework}/20/{solid|outline})
  3. Upgrades your icon names

Thanks to @steveoh & @ryanburns23 for creating the initial list of changes in tailwindlabs/heroicons#750 and to @PicchiKevin for the initial version of this script.


Run

curl https://gist.githubusercontent.com/christiangenco/470a99f4823ee81f2b22bad83119f599/raw/migrateHeroicons.js | node | bash

It definitely works on macOS and should work on linux too. If not you might have to play with the syntax of sed (maybe by replacing sed -i '' -e with sed -i in the gsub function?).

The script will avoid replacing strings in hidden folders and the node_modules folder.

Happy with this script? Come say hi on Twitter @KevinPicchi / @cgenco

const fs = require("fs");
if (!fs.existsSync("package.json")) {
console.error(
"Cannot find package.json. Please run this script in your project directory."
);
process.exit(1);
}
const package = fs.readFileSync("package.json", "utf8");
let framework = null;
if (package.includes("heroicons/react")) {
console.error("Detected heroicons/react...");
framework = "react";
} else if (package.includes("heroicons/vue")) {
console.error("Detected heroicons/vue...");
framework = "vue";
} else {
console.error(
"It doesn't look like you have either the heroicons/react or heroicons/vue libraries installed in this project."
);
process.exit(1);
}
if (fs.existsSync("yarn.lock")) {
console.error("Detected yarn. Updating heroicons package to latest...");
console.log(`yarn add @heroicons/${framework}@latest`);
} else if (fs.existsSync("package-lock.json")) {
console.error("Detected npm. Updating heroicons package to latest...");
console.log(`npm install @heroicons/${framework}@latest`);
} else {
console.error(
"Error: cannot find evidence of yarn or npm. Please run either 'npm install' or 'yarn install' before using this script."
);
process.exit(1);
}
function gsub(from, to) {
console.log(`echo "${from} => ${to}"`);
console.log(
`find -E . -type f -regex '.*\.(js|jsx|ts|tsx|vue)' -not -path '*/\.*' -not -path '*/node_modules/*' -not -path 'migrateHeroicons.js' -exec sed -i '' -e 's|${from}|${to}|g' {} +`
);
}
console.log(`echo "Upgrading import statements..."`);
gsub(`@heroicons/${framework}/solid`, `@heroicons/${framework}/20/solid`);
gsub(`@heroicons/${framework}/outline`, `@heroicons/${framework}/24/outline`);
const heroiconsV1toV2 = {
AdjustmentsIcon: "AdjustmentsVerticalIcon",
AnnotationIcon: "ChatBubbleBottomCenterTextIcon",
ArchiveIcon: "ArchiveBoxIcon",
ArrowCircleDownIcon: "ArrowDownCircleIcon",
ArrowCircleLeftIcon: "ArrowLeftCircleIcon",
ArrowCircleRightIcon: "ArrowRightCircleIcon",
ArrowCircleUpIcon: "ArrowUpCircleIcon",
ArrowNarrowDownIcon: "ArrowLongDownIcon",
ArrowNarrowLeftIcon: "ArrowLongLeftIcon",
ArrowNarrowRightIcon: "ArrowLongRightIcon",
ArrowNarrowUpIcon: "ArrowLongUpIcon",
ArrowsExpandIcon: "ArrowsPointingOutIcon",
ArrowSmDownIcon: "ArrowSmallDownIcon",
ArrowSmLeftIcon: "ArrowSmallLeftIcon",
ArrowSmRightIcon: "ArrowSmallRightIcon",
ArrowSmUpIcon: "ArrowSmallUpIcon",
BadgeCheckIcon: "CheckBadgeIcon",
BanIcon: "NoSymbolIcon",
BookmarkAltIcon: "BookmarkSquareIcon",
CashIcon: "BanknotesIcon",
ChartSquareBarIcon: "ChartBarSquareIcon",
ChatAlt2Icon: "ChatBubbleLeftRightIcon",
ChatAltIcon: "ChatBubbleLeftEllipsisIcon",
ChatIcon: "ChatBubbleOvalLeftEllipsisIcon",
ChipIcon: "CpuChipIcon",
ClipboardCheckIcon: "ClipboardDocumentCheckIcon",
ClipboardCopyIcon: "ClipboardDocumentIcon",
ClipboardListIcon: "ClipboardDocumentListIcon",
CloudDownloadIcon: "CloudArrowDownIcon",
CloudUploadIcon: "CloudArrowUpIcon",
CodeIcon: "CodeBracketIcon",
CollectionIcon: "RectangleStackIcon",
ColorSwatchIcon: "SwatchIcon",
CursorClickIcon: "CursorArrowRaysIcon",
DatabaseIcon: "CircleStackIcon",
DesktopComputerIcon: "ComputerDesktopIcon",
DeviceMobileIcon: "DevicePhoneMobileIcon",
DocumentAddIcon: "DocumentPlusIcon",
DocumentDownloadIcon: "DocumentArrowDownIcon",
DocumentRemoveIcon: "DocumentMinusIcon",
DocumentReportIcon: "DocumentChartBarIcon",
DocumentSearchIcon: "DocumentMagnifyingGlassIcon",
DotsCircleHorizontalIcon: "EllipsisHorizontalCircleIcon",
DotsHorizontalIcon: "EllipsisHorizontalIcon",
DotsVerticalIcon: "EllipsisVerticalIcon",
DownloadIcon: "ArrowDownTrayIcon",
DuplicateIcon: "Square2StackIcon",
EmojiHappyIcon: "FaceSmileIcon",
EmojiSadIcon: "FaceFrownIcon",
ExclamationIcon: "ExclamationTriangleIcon",
ExternalLinkIcon: "ArrowTopRightOnSquareIcon",
EyeOffIcon: "EyeSlashIcon",
FastForwardIcon: "ForwardIcon",
FilterIcon: "FunnelIcon",
FolderAddIcon: "FolderPlusIcon",
FolderDownloadIcon: "FolderArrowDownIcon",
FolderRemoveIcon: "FolderMinusIcon",
GlobeIcon: "GlobeAmericasIcon",
HandIcon: "HandRaisedIcon",
InboxInIcon: "InboxArrowDownIcon",
LibraryIcon: "BuildingLibraryIcon",
LightningBoltIcon: "BoltIcon",
LocationMarkerIcon: "MapPinIcon",
LoginIcon: "ArrowLeftOnRectangleIcon",
LogoutIcon: "ArrowRightOnRectangleIcon",
MailIcon: "EnvelopeIcon",
MailOpenIcon: "EnvelopeOpenIcon",
MenuAlt1Icon: "Bars3CenterLeftIcon",
MenuAlt2Icon: "Bars3BottomLeftIcon",
MenuAlt3Icon: "Bars3BottomRightIcon",
MenuAlt4Icon: "Bars2Icon",
MenuIcon: "Bars3Icon",
MinusSmIcon: "MinusSmallIcon",
MusicNoteIcon: "MusicalNoteIcon",
OfficeBuildingIcon: "BuildingOfficeIcon",
PencilAltIcon: "PencilSquareIcon",
PhoneIncomingIcon: "PhoneArrowDownLeftIcon",
PhoneMissedCallIcon: "PhoneXMarkIcon",
PhoneOutgoingIcon: "PhoneArrowUpRightIcon",
PhotographIcon: "PhotoIcon",
PlusSmIcon: "PlusSmallIcon",
PuzzleIcon: "PuzzlePieceIcon",
QrcodeIcon: "QrCodeIcon",
ReceiptTaxIcon: "ReceiptPercentIcon",
RefreshIcon: "ArrowPathIcon",
ReplyIcon: "ArrowUturnLeftIcon",
RewindIcon: "BackwardIcon",
SaveAsIcon: "ArrowDownOnSquareStackIcon",
SaveIcon: "ArrowDownOnSquareIcon",
SearchCircleIcon: "MagnifyingGlassCircleIcon",
SearchIcon: "MagnifyingGlassIcon",
SelectorIcon: "ChevronUpDownIcon",
SortAscendingIcon: "BarsArrowUpIcon",
SortDescendingIcon: "BarsArrowDownIcon",
SpeakerphoneIcon: "MegaphoneIcon",
StatusOfflineIcon: "SignalSlashIcon",
StatusOnlineIcon: "SignalIcon",
SupportIcon: "LifebuoyIcon",
SwitchHorizontalIcon: "ArrowsRightLeftIcon",
SwitchVerticalIcon: "ArrowsUpDownIcon",
TableIcon: "TableCellsIcon",
TemplateIcon: "RectangleGroupIcon",
TerminalIcon: "CommandLineIcon",
ThumbDownIcon: "HandThumbDownIcon",
ThumbUpIcon: "HandThumbUpIcon",
TranslateIcon: "LanguageIcon",
TrendingDownIcon: "ArrowTrendingDownIcon",
TrendingUpIcon: "ArrowTrendingUpIcon",
UploadIcon: "ArrowUpTrayIcon",
UserAddIcon: "UserPlusIcon",
UserRemoveIcon: "UserMinusIcon",
ViewBoardsIcon: "ViewColumnsIcon",
ViewGridAddIcon: "SquaresPlusIcon",
ViewGridIcon: "Squares2X2Icon",
ViewListIcon: "Bars4Icon",
VolumeOffIcon: "SpeakerXMarkIcon",
VolumeUpIcon: "SpeakerWaveIcon",
XIcon: "XMarkIcon",
ZoomInIcon: "MagnifyingGlassPlusIcon",
ZoomOutIcon: "MagnifyingGlassMinusIcon",
};
console.log(`echo "Upgrading icon names..."`);
Object.entries(heroiconsV1toV2).map(([from, to]) => {
gsub(from, to);
});
console.log(
`echo "Done. You can thank https://twitter.com/cgenco and https://twitter.com/KevinPicchi for saving you so much time :)"`
);
@jemikanegara
Copy link

I think the script will be better if it could automatically target jsx, ts & tsx too

@himynameisubik
Copy link

#165 should be a upper case X and not lower case
ViewGridIcon: "Squares2X2Icon",

Else, handy little script. Thanks a lot!

@christiangenco
Copy link
Author

@jemikanegara Updated to automatically target jsx, ts, and tsx too!

@himynameisubik Good catch. Fixed!

@amerritt14
Copy link

amerritt14 commented Jun 8, 2023

This is amazing!
One thing I noticed is that V2 has a CogIcon but it looks significantly different from V1.
If you want to match the same SVG as V1, You would need to map CogIcon: "Cog8ToothIcon"

Thanks so much!

@imam2nd
Copy link

imam2nd commented Oct 24, 2023

Amazing! Thank you so much for your efforts. I really appreciate it.

@clarkmu
Copy link

clarkmu commented Mar 10, 2024

Nice execution. Thanks

@NicoDMTX
Copy link

NicoDMTX commented Mar 29, 2024

Hello, you could add to your script at line 33

else if (fs.existsSync("pnpm-lock.yaml")) {
  console.error("Detected pnpm. Updating heroicons package to latest...");
  console.log(`pnpm install @heroicons/${framework}@latest`);

I use pnpm in my app and had to change this to make it works

@mreduar
Copy link

mreduar commented May 15, 2024

Because heroicons does not have enough icons to cover all the needs of the project, we found the need to install other icon packs that are compatible with tailwind and at the same time very similar to how heroicons is used. Even many of those other package names match in name with heroicons. This script updates everything that matches the names that were updated. Running it also updated other names of other icon packs I have and broke most of the application. It is recommended to use it only if you don't have any other package that may have name conflicts with heroicons.

Besides that, I had to modify the script slightly to be supported on my machine, this is a mac script, on linux it doesn't work because the -E option is not supported on all versions of find. It is specific to some versions of BSD find (such as macOS) and is not compatible with the GNU find version commonly found on Linux systems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment