Phát triển phần mềm
Gần đây tôi đã thi sát hạch lái xe hạng hai và cảm thấy như một kỳ thi không phải là thi tốt nghiệp THPT nhưng lại giống như vậy (chênh lệch 10 năm trước chỉ có 5 điểm, vẫn chưa thể tha thứ được)!
Tám người cùng ngồi một chiếc xe, chỉ có tôi học ít nhất (4 ngày, 8 người chia sẻ một xe), huấn luyện viên đều nghĩ rằng tôi chắc chắn sẽ phải thi lại!
Nhờ may mắn và niềm tin, tôi đã vượt qua các phần thi đỗ xe ngang và lùi xe vào khoảng trống một cách đầy rủi ro, cuối cùng cũng an ủi được trái tim trẻ trung 10 năm trước!
——————————Kết thúc cảm xúc, quay lại chủ đề——————————
Sau khi sửa xong các lỗi mà khách hàng gửi, tôi tiến hành phát hành, cập nhật, kiểm thử, gửi email thông báo, vui vẻ duyệt blog园... rồi khách hàng gọi đến...
Khách hàng: Tại sao yêu cầu của tôi không được sửa? Mà nút này màu vẫn chưa đổi, hiệu ứng khi nhấn vẫn cũ, giao diện cũng chưa thay đổi...!@#$%^&*...
Tôi: Tôi thấy ở đây đều bình thường, tôi gửi ảnh chụp màn hình cho bạn xem...
Khách hàng: Vậy anh remote xem thử có gì sai không.
Tôi: À, trình duyệt đang cache, hãy làm mới bằng Ctrl+F5, trên điện thoại...!@#$%^&*...
Khách hàng: (° ?°)~@
——————————Trò chuyện trên là từ thực tế, nếu trùng lặp thì là chuyện bình thường——————————
Mỗi lần cập nhật, lại xảy ra tình huống tương tự, mỗi lần giải thích mãi cũng vô ích, cuối cùng phải thêm ký tự ?v=111 cho từng tệp js, css, tốn công tốn sức mà không được hoan nghênh.
Sau đó dùng combres tưởng sẽ ổn, nhưng việc thêm tham chiếu js và css trở nên phức tạp hơn, mỗi lần chỉnh sửa cấu hình cũng khó khăn, đồng nghiệp không muốn dùng nữa.
Cuối cùng, buộc phải yêu cầu mọi người thêm ?v=xxx khi chỉnh sửa, tự kỷ dễ nhưng khiến người khác làm thì khó, lại còn thao tác không tiện, mọi người càng không muốn làm.
Nếu bạn không tự chỉnh sửa, vấn đề sẽ luôn tồn tại, chỉ tăng không giảm...
Nhập nhanh
Sau này tôi phát hiện ra rằng Visual Studio có chức năng kéo đoạn mã vào thanh công cụ, nhấn vào để nhập nhanh, hiệu quả rất tiện lợi, lúc đó tôi nghĩ nếu số phiên bản js và css cũng có thể nhập nhanh thì mọi người sẽ dễ làm hơn, nhưng vì nội dung cố định nên việc dùng vẫn không tiện. Vì vậy, đường dài còn xa, tôi sẽ tìm kiếm!
Phát triển trình bổ trợ Visual Studio – tự làm tự ăn
Khi đọc bài viết "Lợi ích cho người rối loạn tính chính xác – Trình bổ trợ Visual Studio đầu tiên của tôi, sắp xếp using!" tôi biết: chỉ cần bạn muốn, điều đó là có thể. Về việc cài đặt VisualStudio SDK, tạo dự án,... các bài viết trước đã nói rõ rồi. Nếu có hứng thú, có thể truy cập liên kết bài viết trước!
Chỉ cần chỉnh sửa vài cấu hình nhỏ, chủ yếu là biểu tượng, phím tắt, tên menu. Đây là tệp cấu hình hoàn chỉnh của tôi:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Tệp này định nghĩa bố cục và loại lệnh thực tế.
Nó được chia thành nhiều phần (ví dụ: định nghĩa lệnh, vị trí lệnh, ...) với mỗi phần định nghĩa một tập hợp thuộc tính cụ thể.
Xem chú thích trước mỗi phần để hiểu rõ cách sử dụng. -->
<!-- Công cụ biên dịch VSCT (công cụ chuyển đổi tệp này sang định dạng nhị phân mà VisualStudio tiêu thụ) có khả năng chạy tiền xử lý trên tệp vsct; tiền xử lý này thường là trình tiền xử lý C++, vì vậy có thể định nghĩa include và macro bằng cú pháp tương tự tệp C++. Sử dụng khả năng này của trình biên dịch, chúng ta include một số tệp định nghĩa một số hằng số dùng trong tệp. -->
<!--Tệp này định nghĩa ID cho tất cả các lệnh được cung cấp bởi VisualStudio. -->
<Extern href="stdidcmd.h"/>
<!--Tệp này chứa ID lệnh cho các menu do shell cung cấp. -->
<Extern href="vsshlids.h"/>
<!--Phần Lệnh là nơi định nghĩa lệnh, menu và nhóm menu.
Phần này sử dụng Guid để xác định gói cung cấp lệnh được định nghĩa bên trong nó. -->
<Commands package="guidfillVersionPackage">
<!-- Bên trong phần này có nhiều phần con: menu, nhóm menu, nút (lệnh thực tế), hộp chọn và phần bitmap dùng. Mỗi phần được xác định bởi ID lệnh là một cặp duy nhất gồm guid và số định danh; phần guid của ID thường gọi là "tập lệnh" dùng để nhóm các lệnh liên quan logic; gói của bạn nên định nghĩa tập lệnh riêng để tránh xung đột với ID lệnh được định nghĩa bởi các gói khác. -->
<!-- Trong phần này bạn có thể định nghĩa nhóm menu mới. Một nhóm menu là container cho các menu hoặc nút (lệnh) khác; từ góc nhìn trực quan bạn có thể xem nhóm như phần menu giữa hai đường kẻ. Người cha của nhóm phải là một menu. -->
<Groups>
<Group guid="guidfillVersionPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
</Groups>
<!--Phần nút. -->
<!--Phần này định nghĩa các phần tử mà người dùng có thể tương tác, ví dụ như lệnh menu hoặc nút hoặc hộp chọn trong thanh công cụ. -->
<Buttons>
<!--Để định nghĩa nhóm menu bạn phải xác định ID, menu cha và mức ưu tiên hiển thị.
Lệnh mặc định là hiển thị và bật. Nếu bạn cần thay đổi sự hiện thị, trạng thái,... bạn có thể dùng phần tử CommandFlag.
Bạn có thể thêm nhiều phần tử CommandFlag ví dụ:
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
Nếu bạn không muốn hình ảnh bên cạnh lệnh, hãy xóa phần tử Icon /> -->
<Button guid="guidfillVersionPackageCmdSet" id="fillVersionId" priority="0x0100" type="Button">
<Parent guid="guidfillVersionPackageCmdSet" id="MyMenuGroup" />
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
<ButtonText>Đặt phiên bản</ButtonText>
</Strings>
</Button>
</Buttons>
<!--Phần bitmap dùng để định nghĩa bitmap cho các lệnh.-->
<Bitmaps>
<!-- ID bitmap được định nghĩa theo cách hơi khác so với các phần khác:
khai báo bắt đầu bằng guid cho bảng bitmap, sau đó là ID tài nguyên của bảng bitmap chứa các bitmap và cuối cùng là ID số của các phần tử được dùng trong định nghĩa nút. Một điểm quan trọng trong khai báo này là ID phần tử phải là chỉ mục thực tế (dựa trên 1) của bitmap trong bảng bitmap. -->
<Bitmap guid="guidImages" href="Resources\fillVersion.png" usedList="bmpPic1"/>
</Bitmaps>
</Commands>
<KeyBindings>
<!-- Đặt phím tắt là alt+J. -->
<KeyBinding guid="guidfillVersionPackageCmdSet" id="fillVersionId" editor="guidVSStd97" key1="J" mod1="ALT" />
</KeyBindings>
<Symbols>
<!-- Đây là guid của gói. -->
<GuidSymbol name="guidfillVersionPackage" value="{67c49ffd-7eca-4805-9b45-a837fb03a08c}" />
<!-- Đây là guid dùng để nhóm các lệnh menu lại -->
<GuidSymbol name="guidfillVersionPackageCmdSet" value="{af86a8d5-ac26-40b6-be11-0fcf3d9bd974}">
<IDSymbol name="MyMenuGroup" value="0x1020" />
<IDSymbol name="fillVersionId" value="0x0100" />
</GuidSymbol>
<GuidSymbol name="guidImages" value="{da500753-6754-4737-82c4-2b65d5e9ad59}" >
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
</Symbols>
</CommandTable>
Sau khi dựng xong dự án và cấu hình xong, bắt đầu thực hiện.
Món ăn nhẹ phiên bản đầu tiên
Chúng ta biết logic menu nằm trong fillVersion.cs -〉 MenuItemCallback
Phiên bản đầu tiên rất đơn giản, chỉ cần nhập ?v=yyyyMMddss, bề ngoài đã thực hiện ý tưởng của tôi, thực sự tiện hơn trước rất nhiều, chỉ cần nhấn phím tắt là hoàn thành hiệu quả của nhiều lần nhập trước đó, mã nguồn như sau:
1 var dte = this.ServiceProvider.GetService(typeof(DTE)) as DTE;
2 var selection = dte.ActiveDocument.Selection as TextSelection;//Vùng đã chọn trong tài liệu hiện tại
3 if (selection == null)
4 {
5 return;
6 }
8 string versionstr = "?v=" + DateTime.Now.ToString("yyyyMMddss");
9 selection.Insert(versionstr, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd);//Ghi lại vào tài liệu
Hiệu quả như sau:
Nhưng vấn đề xuất hiện:
A, Con trỏ phải được đặt ngay sau tên tệp, điều này không tạo ra khó khăn sao?
B, Tôi muốn thêm phiên bản cho vài tệp js cùng lúc, làm thế nào? Nhập từng cái? Điều này vẫn tạo ra khó khăn sao?
C, Tôi muốn thêm phiên bản cho cả js và css cùng lúc thì sao?
...
Với những câu hỏi này, tôi bắt đầu hành trình mới.
Món ăn nhẹ phiên bản cuối cùng
Giải quyết các vấn đề trong phiên bản đầu tiên, trước tiên chúng ta cần phân tích nội dung đã chọn, tìm kiếm trên Google, tôi phát hiện ra HtmlAgilityPack, công việc sau đó trở nên đơn giản, duyệt các thẻ script và link, lấy thuộc tính href, src, thêm ?v=yyyyMMddss là xong.
Phiên bản này, chúng ta có thể đặt phiên bản cho nhiều thẻ cùng lúc, thao tác tiện lợi hơn. Khi thuận tiện, đồng nghiệp tự nhiên muốn dùng, không cần tôi yêu cầu nữa.
Hãy xem mã nguồn, mọi người nhìn là hiểu, không có chú thích vì mã nguồn chính là chú thích tốt nhất.
1 var dte = this.ServiceProvider.GetService(typeof(DTE)) as DTE;
2 var selection = dte.ActiveDocument.Selection as TextSelection;//Vùng đã chọn trong tài liệu hiện tại
3 if (selection == null)
4 {
5 return;
6 }
7
8 HtmlDocument doc = new HtmlDocument();
9 doc.LoadHtml(selection.Text);
10
11 HtmlNodeCollection script = doc.DocumentNode.SelectNodes("//script");
12 HtmlNodeCollection link = doc.DocumentNode.SelectNodes("//link");
13
14 string newcontent = "";
15 string versionstr = "?v=" + DateTime.Now.ToString("yyyyMMddss");
16
17 if (link != null)
18 {
19 foreach (HtmlNode categoryNode in link)
20 {
21 string href = categoryNode.Attributes["href"].Value;
22 if (href.IndexOf("?") > 0)
23 {
24 href = href.Substring(0, href.IndexOf("?"));
25 }
26 href += versionstr;
27 newcontent += "<link type=\"text/css\" rel=\"stylesheet\" href=\"" + href + "\" />\r\n";
28 }
29 }
30
31
32 if (script != null)
33 {
34 foreach (HtmlNode categoryNode in script)
35 {
36 string src = categoryNode.Attributes["src"].Value;
37 if (src.IndexOf("?") > 0)
38 {
39 src = src.Substring(0, src.IndexOf("?"));
40 }
41 src += versionstr;
42 newcontent += "<script src=\"" + src + "\"></script>\r\n";
43 }
44
45 }
46
47 if (newcontent.Length == 0)
48 {
49 newcontent = versionstr;
50 }
51
52 selection.Insert(newcontent, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd);//Ghi lại vào tài liệu
Thêm vài hình ảnh cuối cùng, có hình có thật, phía sau còn có mã nguồn nhé (về icon HJ là để tặng vợ tôi \\*^o^*//).
(Chọn một dòng)
(Chọn nhiều dòng, chứa thẻ link, script)
Kết luận
Mặc dù plugin này đơn giản, nhưng quá trình phát triển mất vài buổi tối. Cá nhân tôi thấy rất hữu ích (ít nhất với chúng tôi trong phát triển phần mềm), nên chia sẻ với mọi người (phía sau sẽ có file cài đặt và mã nguồn).
Nếu thấy hữu ích, hãy bấm like để vui vẻ; nếu thấy viết không hay, cũng đừng ngại ném đá; nếu có chỗ sai, xin vui lòng góp ý để cùng tiến bộ!
File cài đặt, nhấn tải xuống (được phát triển với VS2015, nếu không cài được thì tự biên dịch nhé)
Mã nguồn, nén còn 11MB, chỉ có thể upload lên CSDN miễn phí. Nhấn tải xuống.
Trở thành lập trình viên xuất sắc!