合并脚本和样式表_缩小并连接您的脚本和样式表

合并脚本和样式表

Today is the age of broadband.  More and more people are going this route determined to experience the web and it’s multitude of services as quickly and painlessly as possible. Coupled with the move to broadband, people are experiencing the web via their mobile devices – and it is this which most developers/designers forget.

今天是宽带时代。 越来越多的人决定沿着这种方式体验网络,并尽可能快速,轻松地体验各种服务。 伴随着向宽带的迁移,人们正在通过他们的移动设备体验网络-而这正是大多数开发人员/设计人员所忘记的。

With mobile devices becoming mainstream, it is more important than ever that we as designers and developers convey the importance of optimized web sites to our clients. With this in mind, I would like to introduce some strategies I use when developing a website, or web application.

随着移动设备成为主流,我们作为设计师和开发人员向客户传达优化网站的重要性比以往任何时候都更为重要。 考虑到这一点,我想介绍一些在开发网站或Web应用程序时使用的策略。

#1 Make sure no matter how many CSS stylesheets you use, they are placed in between your <head> tags.  This will make sure that your styling gets rendered by the browser in a timely manner relative to the rendering of the page.

#1确保无论使用多少CSS样式表,它们都放置在<head>标记之间。 这将确保您的样式相对于页面的呈现被浏览器及时呈现。

#2 Wherever possible, combine your stylesheets into one.  This will decrease page load time by cutting down the parrellel downloads the browser has to make to request your page.  If you absolutely must have mutliple stylesheets, see below for a code snippet that will do this on the fly for you.  (written in VB.NET)

#2尽可能将样式表合并为一个。 通过减少浏览器请求您的页面所需的并行下载,这将减少页面加载时间。 如果您绝对必须有多个样式表,请参见下面的代码段,这些代码段将为您快速完成。 (用VB.NET编写)

#3 We all love javascript, I personally am a big fan of jQuery, and the jQuery UI.  Make sure that no matter how many javascript includes you have, they are placed at the very bottom of the page right before the </body> tag.  This will make sure the page is rendered before any javascript can interupt the document.

#3我们都喜欢javascript,我个人是jQuery和jQuery UI的忠实拥护者。 确保无论您包含多少个javascript,它们都位于页面</ body>标记之前的最底部。 这将确保在任何javascript可以插入文档之前,已呈现页面。

#4 Wherever possible, combine your script files into one.  This will decrease page load time by cutting down on the parrellel downloads the browser has to make to request your page.  If you absolutely must have mutliple script files, see below for a code snippet that will do this on the fly for you.  (written in VB.NET)

#4尽可能将脚本文件合并为一个。 通过减少浏览器请求页面所需的并行下载,这将减少页面加载时间。 如果您绝对必须具有多个脚本文件,请参见下面的代码段,这些代码段将为您快速完成。 (用VB.NET编写)

#5 Minify both your scripts and stylesheets to achieve optimal download times.  This will help your pages load faster – less size, less time to render the page.

#5最小化脚本和样式表,以达到最佳下载时间。 这将帮助您的页面加载更快–尺寸更小,呈现页面的时间更少。

#6 Enable GZip encoding.  This will further compress your files making for a faster loading page.

#6启用GZip编码。 这将进一步压缩文件,从而加快页面加载速度。

#7 Wherever possible: Cache, Cache, Cache.  I can't say it enough to emphasize how important it is to leverage both server and client caching.  This will reduce the number of times your browser has to hit the server for a page request.

#7只要有可能:缓存,缓存,缓存。 我不能说足够多来强调利用服务器和客户端缓存的重要性。 这将减少您的浏览器必须点击服务器才能进行页面请求的次数。

Now without further ado, is some handy, helpful code that will take your page output, parse it for script and css linked stylesheets, combine them into one "file" each, "minify" them, "cache" them and then render them to the browser.

现在,事不宜迟,这里有一些方便,有用的代码,它们将带您的页面输出,将其解析为脚本和CSS链接的样式表,将它们分别组合为一个“文件”,“最小化”它们,“缓存”它们,然后将它们呈现为浏览器。

To be honest, there may be better methods to do this minification, however, in my 'production' environment, what I have listed below is what has worked best for me.

老实说,可能有更好的方法来实现这种最小化,但是,在我的“生产”环境中,下面列出的是最适合我的方法。

This main processing of this project contains five files, and for testing purposes I added four javascript files, two stylesheets, and a default page to test with.

该项目的主要处理过程包含五个文件,出于测试目的,我添加了四个javascript文件,两个样式表和一个默认页面进行测试。

First things first, let's get the common stuff out of the way. I have aptly named this Common.vb and this should be placed in your 'App_Code' directory:

首先,让我们摆脱常见的问题。 我已恰当地命名了此Common.vb,并将其放置在您的“ App_Code”目录中:

Imports Microsoft.VisualBasic

''' <summary>
''' Our common class file
''' </summary>
''' <remarks></remarks>
Public Class Common

    ''' <summary>
    ''' Let's cache this stuff
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub CacheIt()
        ' Allow the browser to store resposes in the 'History' folder
        HttpContext.Current.Response.Cache.SetAllowResponseInBrowserHistory(True)
        ' Set our cacheability to Public
        HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.Public)
        ' Resource is valid until the expiration has passed
        HttpContext.Current.Response.Cache.SetValidUntilExpires(True)
        ' Set out last modified date to last year
        HttpContext.Current.Response.Cache.SetLastModified(Date.Now.AddDays(-366))
        ' We want to store and cache the resource
        HttpContext.Current.Response.AddHeader("Cache-Control", "store, cache")
        ' Set the Pragma to cache
        HttpContext.Current.Response.AddHeader("pragma", "cache")
        ' Not sure if this one really works, but it doesn't throw an error, and Google likes resources served from a cookie-less domain... eh... worth a shot
        HttpContext.Current.Response.AddHeader("Set-Cookie", "false")
        ' Make sure our cache control is Public
        HttpContext.Current.Response.CacheControl = "public" '
        'Set the expiration date of the resource until next year
        HttpContext.Current.Response.Expires = 24 * 60 * 366
        HttpContext.Current.Response.ExpiresAbsolute = DateAdd(DateInterval.Hour, 24 * 366, Date.Now)
    End Sub

    ''' <summary>
    ''' Let's check to see if the browser accepts GZip encoding
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsGZipEnabled() As Boolean
        Dim accEncoding As String = HttpContext.Current.Request.Headers("Accept-Encoding")
        'Does the browser accept content encoding?
        If (Not accEncoding Is Nothing) Then
            If (accEncoding.Contains("gzip") Or accEncoding.Contains("deflate")) Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

End Class

Now let's get down to business.  This is the code that will do the concatenation and minification.  Place it in your 'App_Code' folder. Yes folks, it is an HttpModule:

现在让我们开始做生意。 这是将进行串联和最小化的代码。 将其放在您的“ App_Code”文件夹中。 是的,这是一个HttpModule:

Imports System.IO.Compression
Imports System.Web
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.IO
Imports System.Web.Compilation

''' <summary>
''' Dynamic compression mechanism for some of the sites content
''' </summary>
''' <remarks></remarks>
Public Class DynamicCompression
    Implements IHttpModule

    ''' <summary>
    ''' Initialize our module
    ''' </summary>
    ''' <param name="application"></param>
    ''' <remarks></remarks>
    Public Sub Init(ByVal application As HttpApplication) _
        Implements IHttpModule.Init
        'Add the BeginRequest Handler
        AddHandler application.BeginRequest, _
            AddressOf Me.Application_BeginRequest
        Dim context As HttpContext = application.Context
        'Let's see if the browser accepts GZip encoding, if it does add the header to the response
        If Common.IsGZipEnabled() Then
            Dim accEncoding As String = context.Request.Headers("Accept-Encoding")
            If accEncoding.Contains("gzip") Then
                context.Response.Filter = New GZipStream(context.Response.Filter, CompressionMode.Compress)
                context.Response.AppendHeader("Content-Encoding", "gzip")
            Else
                context.Response.Filter = New DeflateStream(context.Response.Filter, CompressionMode.Compress)
                context.Response.AppendHeader("Content-Encoding", "deflate")
            End If
        End If
    End Sub

    ''' <summary>
    ''' Begin the request and process our filter
    ''' </summary>
    ''' <param name="source"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Application_BeginRequest(ByVal source As Object, ByVal e As EventArgs)
        Dim application As HttpApplication = DirectCast(source, HttpApplication)
        Dim context As HttpContext = application.Context
        Dim filePath As String = context.Request.FilePath
        Dim fileExtension As String = VirtualPathUtility.GetExtension(filePath)
        If fileExtension.Equals(".aspx") Then
            application.Response.Filter = New Worker(application.Response.Filter, source)
        End If
    End Sub

    ''' <summary>
    ''' Unneeded for our purposes
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
    End Sub

    ''' <summary>
    ''' Let's do the actual work
    ''' </summary>
    ''' <remarks></remarks>
    Private Class Worker
        Inherits Stream

        ''' <summary>
        ''' Get our application context and file stream
        ''' </summary>
        ''' <param name="sink"></param>
        ''' <param name="source"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal sink As Stream, ByVal source As Object)
            _sink = sink
            Dim application As HttpApplication = DirectCast(source, HttpApplication)
            context = application.Context
        End Sub

#Region "Properites"

        ''' <summary>
        ''' These properties are a necessary implementation when we inherit IO.Stream
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>

        Public Overrides ReadOnly Property CanRead() As Boolean
            Get
                Return True
            End Get
        End Property

        Public Overrides ReadOnly Property CanSeek() As Boolean
            Get
                Return True
            End Get
        End Property

        Public Overrides ReadOnly Property CanWrite() As Boolean
            Get
                Return True
            End Get
        End Property

        Public Overrides Sub Flush()
            _sink.Flush()
        End Sub

        Public Overrides ReadOnly Property Length() As Long
            Get
                Return 0
            End Get
        End Property

        Private _position As Long
        Public Overrides Property Position() As Long
            Get
                Return _position
            End Get
            Set(ByVal value As Long)
                _position = value
            End Set
        End Property

        Private _sink As Stream
        Private context As HttpContext
        Private html As String, FileCSS As String, FileJS As String

#End Region

#Region "Methods"

        ''' <summary>
        ''' Most of these methods are here because they are necessary for inheriting IO.Stream
        ''' They will make sure we are handling the stream correctly
        ''' </summary>
        ''' <param name="buffer"></param>
        ''' <param name="offset"></param>
        ''' <param name="count"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>

        Public Overrides Function Read(ByVal buffer As Byte(), ByVal offset As Integer, ByVal count As Integer) As Integer
            Return _sink.Read(buffer, offset, count)
        End Function

        Public Overrides Function Seek(ByVal offset As Long, ByVal origin As SeekOrigin) As Long
            Return _sink.Seek(offset, origin)
        End Function

        Public Overrides Sub SetLength(ByVal value As Long)
            _sink.SetLength(value)
        End Sub

        Public Overrides Sub Close()
            _sink.Close()
        End Sub

        ''' <summary>
        ''' Overwride the default response write, so we can pass the stream back to the browser
        ''' </summary>
        ''' <param name="buffer__1"></param>
        ''' <param name="offset"></param>
        ''' <param name="count"></param>
        ''' <remarks></remarks>
        Public Overrides Sub Write(ByVal buffer__1 As Byte(), ByVal offset As Integer, ByVal count As Integer)
            Dim data As Byte() = New Byte(count - 1) {}
            Buffer.BlockCopy(buffer__1, offset, data, 0, count)
            html = System.Text.Encoding.[Default].GetString(buffer__1)
            'CSS
            CompressStyles(html)
            'JS
            CompressJavascript(html)
            Dim outdata As Byte() = System.Text.Encoding.[Default].GetBytes(html)
            _sink.Write(outdata, 0, outdata.GetLength(0))
        End Sub

        ''' <summary>
        ''' Grab our stylesheets from the file stream string
        ''' concatenate it, minify it, and pass back the originating string while replacing all the stylesheet references
        ''' with a single refernce to our new stylesheet file
        ''' </summary>
        ''' <param name="StrFile"></param>
        ''' <remarks></remarks>
        Private Sub CompressStyles(ByVal StrFile As String)
            Dim FilesM As MatchCollection, FileName As String
            FilesM = Regex.Matches(StrFile, "<link.*?href=""(.*?)"".*? />")
            Dim M(FilesM.Count - 1) As String
            For i As Long = 0 To M.Length - 1
                'This is the file
                M(i) = FilesM(i).Groups(1).Value
                FileName = HttpContext.Current.Server.MapPath(M(i).Replace("/", "\"))
                FileName = FileName.Replace("\\\", "\")
                If File.Exists(FileName) Then
                    Using objFile As New StreamReader(FileName)
                        FileCSS += objFile.ReadToEnd
                        objFile.Close()
                    End Using
                    FileCSS = Regex.Replace(FileCSS, "/\*.+?\*/", "", RegexOptions.Singleline)
                    FileCSS = FileCSS.Replace("  ", "")
                    FileCSS = FileCSS.Replace(vbCr, "")
                    FileCSS = FileCSS.Replace(vbLf, "")
                    FileCSS = FileCSS.Replace(vbCrLf, "")
                    FileCSS = FileCSS.Replace(vbTab, " ")
                    FileCSS = FileCSS.Replace("\t", "")
                    FileCSS = FileCSS.Replace(" {", "{")
                    FileCSS = FileCSS.Replace("{ ", "{")
                    FileCSS = FileCSS.Replace(" }", "}")
                    FileCSS = FileCSS.Replace("} ", "}")
                    FileCSS = FileCSS.Replace(" :", ":")
                    FileCSS = FileCSS.Replace(": ", ":")
                    FileCSS = FileCSS.Replace(", ", ",")
                    FileCSS = FileCSS.Replace("; ", ";")
                    FileCSS = FileCSS.Replace(";}", "}")
                    FileCSS = Regex.Replace(FileCSS, "/\*[^\*]*\*+([^/\*]*\*+)*/", "$1")
                End If
            Next
            FilesM = Nothing
            If context.Cache("CSS") Is Nothing Then
                context.Cache.Add("CSS", FileCSS, Nothing, DateTime.Now.AddDays(31), Cache.NoSlidingExpiration, CacheItemPriority.High, Nothing)
            End If
            Dim tmp As MatchCollection
            tmp = Regex.Matches(StrFile, "<link.*?href=""(.*?)"".*? />")
            Dim tmpCt As Long = 0
            For Each tmpS As Match In tmp
                tmpCt += 1
                If tmpCt = tmp.Count Then
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), "<link type=""text/css"" rel=""stylesheet"" href=""/Style.aspx"" />")
                Else
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), String.Empty)
                End If
            Next
            tmp = Nothing
            html = StrFile
        End Sub

        ''' <summary>
        ''' Grab our scripts from the file stream string
        ''' concatenate it, minify it, and pass back the originating string while replacing all the scripts references
        ''' with a single refernce to our new scripts file
        ''' </summary>
        ''' <param name="StrFile"></param>
        ''' <remarks></remarks>
        Private Sub CompressJavascript(ByVal StrFile As String)
            Dim FilesM1 As MatchCollection, FileName As String
            FilesM1 = Regex.Matches(StrFile, "<script.*?src=""(.*?)"".*?></script>")
            Dim M1(FilesM1.Count - 1) As String
            For j As Long = 0 To M1.Length - 1
                'This is the file
                M1(j) = FilesM1(j).Groups(1).Value
                FileName = HttpContext.Current.Server.MapPath(M1(j).Replace("/", "\"))
                FileName = FileName.Replace("\\\", "\")
                If File.Exists(FileName) Then
                    Using objFile1 As New StreamReader(FileName)
                        FileJS += objFile1.ReadToEnd
                        objFile1.Close()
                    End Using
                    FileJS = Regex.Replace(FileJS, "(// .*?$)", "", RegexOptions.Multiline)
                    FileJS = Regex.Replace(FileJS, "(/\*.*?\*/)", "", RegexOptions.Multiline)
                    FileJS = FileJS.Replace("  ", " ")
                    FileJS = FileJS.Replace(vbCr, vbLf)
                    FileJS = FileJS.Replace(vbCrLf, vbLf)
                    FileJS = FileJS.Replace(vbTab, " ")
                End If
            Next
            If context.Cache("JS") Is Nothing Then
                context.Cache.Add("JS", FileJS, Nothing, DateTime.Now.AddDays(31), Cache.NoSlidingExpiration, CacheItemPriority.High, Nothing)
            End If
            FilesM1 = Nothing
            Dim tmp1 As MatchCollection
            tmp1 = Regex.Matches(StrFile, "<script.*?src=""(.*?)"".*?></script>")
            Dim tmpCt1 As Long = 0
            For Each tmpS As Match In tmp1
                tmpCt1 += 1
                If tmpCt1 = tmp1.Count Then
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), "<script type=""text/javascript"" src=""/Script.aspx""></script>")
                Else
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), String.Empty)
                End If
            Next
            tmp1 = Nothing
            html = StrFile
        End Sub

#End Region

    End Class

End Class

Once you have added in the module, you will need to make a modification to register the module for the application.

一旦添加了模块,就需要进行修改以为应用程序注册模块。

This section goes in your web.config file for the site:

此部分位于站点的web.config文件中:

<add name="DynamicCompression" type="DynamicCompression"/>

and needs to be in the <system.web><httpModules> section.

并且必须位于<system.web> <httpModules>部分中。

Now that we have the grunts out of the way, let's add in our 'extra' files that will be needed to process these resources:

现在,我们已经不再烦恼了,让我们添加处理这些资源所需的“额外”文件:

First we have Script.aspx which needs to be placed in the root of the website.

首先,我们需要将Script.aspx放置在网站的根目录中。

<%@ Page Language="VB" %>
<% 
    'Cache our response in the browser
    Common.CacheIt()
    'Set the content type to output true CSS
    Response.ContentType = "text/css"
    If Not (Cache("CSS") Is Nothing) Then
        'Write it out from the cache
        Response.Write(Cache("CSS").ToString())
    End If
    %>

Next we'll add in Script.aspx and that needs to be placed in the root of the website as well.

接下来,我们将添加Script.aspx,并将其也放置在网站的根目录中。

<%@ Page Language="VB" %>
<% 
    'Cache our response in the browser
    Common.CacheIt()
    'Set the content type to output true javascript
    Response.ContentType = "text/javascript"
    If Not (Cache("JS") Is Nothing) Then
        'write out the javascript string from our cache
        Response.Write(Cache("JS").ToString())
    End If
    %>

All that is left is to include your stylesheets and javascript includes and you are good to go.

剩下的就是包含您的样式表和javascript包含,您很高兴。

Here is our Default.aspx that is the default page for the site...real simple:

这是我们的Default.aspx,它是网站的默认页面...非常简单:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Untitled Page</title>
        <meta http-equiv="Content-Script-Type" content="text/javascript" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
        <link href="/styles/layout1.css" rel="stylesheet" type="text/css" />
        <link href="/styles/layout2.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        Just a test to make sure the CSS and JS works
        <a href="javascript:;" onclick="alert($('body').html());">Click Here</a>
        <script type="text/javascript" src="/scripts/jquery.js"></script>
        <script type="text/javascript" src="/scripts/jquery.pngFix.pack.js"></script>
        <script type="text/javascript" src="/scripts/jquery.preloadcssimages.js"></script>
        <script type="text/javascript" src="/scripts/custom.js"></script>
    </body>
</html>

And that would be that.  Compile the site and run it, and you will see the benefits of the work at hand.

那就是那样。 编译站点并运行它,您将看到手头工作的好处。

Please make sure to leave me any suggestions, improvements, and/or comments you may have, as I am always open for improvements.

请务必留下任何建议,改进和/或意见,因为我一直乐意改进。

Happy Coding!

编码愉快!

p.s.  Here is the complete project:  Test.zip

ps这是完整的项目: Test.zip

翻译自: https://www.experts-exchange.com/articles/4334/Minify-and-Concatenate-Your-Scripts-and-Stylesheets.html

合并脚本和样式表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值