前端

How Smart Tools Are Shaping the Future of Creative Work

Eric Chuang
2020-11-01

這次公司的網站更新,同時又接觸了新技能:Grunt。

以前在執行靜態檔案最佳化,都是透過快取外掛 W3 Total Cache 協助執行,但是有時最小化之後會出錯 (可能在最小化 JavaScript 時,變數或函式互相干擾),因此想要自己可以控制最小化的任務。這次執行最小化後,將原本的 CSS 檔案縮小了 33% (70 kb → 47kb),JavaScript 檔案也都縮小了 30-50%。

如同官方網站的次標題:the JavaScript Task Runner,Grunt 是一款奠基於 Node.js 之上的任務管理套件。在使用 Grunt 前,需要先能夠從 NPM 中安裝套件。關於 NPM 的使用方法,可以參考這篇文章,這裡就不再贅述。

安裝 Grunt

在開始使用 Grunt 以前,需要先透過 NPM 安裝 Grunt。打開終端機/命令提示字元,並輸入 NPM 的安裝指令,在全域安裝 Grunt CLI。

npm install -g grunt-cli

接著在你的專案資料夾中,編輯你的 package.json 檔案,加入以下相依套件:

{
  "name": "my-project-name",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0"
  }
}

執行 npm install 指令,將相依套件安裝至專案資料夾中。

編輯 Gruntfile.js 檔案

module.exports = function(grunt) {
	// Project configuration.
	grunt.initConfig( {
		pkg: grunt.file.readJSON( 'package.json' ),
	} );
};

grunt.file.readJSON('package.json') 這項指令是用以讀取 package.json 中的套件中繼資料。

接著加入任務名稱,並載入任務套件。以這次的範例為例,我想要最小化我的靜態話資源 (CSS 與 JavaScript 檔案),因此我使用了 terser、autoprefixer、sass 與 cssmin。

module.exports = function ( grunt ) {
	// Project configuration.
	grunt.initConfig( {
		pkg: grunt.file.readJSON( 'package.json' ),
	} );

	// Load the plugin that provides the "uglify" task.
	grunt.loadNpmTasks( 'grunt-terser' );
	grunt.loadNpmTasks( 'grunt-autoprefixer' );
	grunt.loadNpmTasks( 'grunt-contrib-sass' );
	grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
};

同時記得在終端機/命令提示字元中執行 NPM 指令,安裝上述套件。

npm install --save-dev grunt-terser grunt-autoprefixer grunt-contrib-sass grunt-contrib-cssmin

加入任務組態

Terser 是一款最小化 JavaScript 檔案的套件,在 Gruntfile.js 中加入選項與組態:

module.exports = function ( grunt ) {
	// Project configuration.
	grunt.initConfig( {
		pkg: grunt.file.readJSON( 'package.json' ),
		terser: {
			options: {
				mangle: {
					toplevel: true,
				},
			},
			build: {
				files: [
					{
						expand: true,
						src: [ 'js/*.js', '!js/*.min.js' ],
						ext: '.min.js',
					},
				],
			},
		},
	} );

	// Load the plugin that provides the "uglify" task.
	grunt.loadNpmTasks( 'grunt-terser' );
	grunt.loadNpmTasks( 'grunt-autoprefixer' );
	grunt.loadNpmTasks( 'grunt-contrib-sass' );
	grunt.loadNpmTasks( 'grunt-contrib-cssmin' );

	// Default task(s).
	grunt.registerTask( 'default', [
		'terser',
		'sass',
		'autoprefixer',
		'cssmin',
	] );
};

mangle 是用來將 JavaScript 中的變數與屬性改以單個字母表現,例如 let findMyCookie 會被壓縮為 let f。這種作法可以有效的減少 JavaScript 的檔案大小。

toplevel 則是讓 mangle 的適用範圍只及於最上層的變數與函式名稱。

build 中則是指定要適用的檔案範圍,expand: true 會去自動偵測路徑,js/*.js 代表要包含 js 這個資料夾中的所有副檔名為 js 的檔案,而 !js/*.min.js 代表不要再去壓縮是壓縮檔的檔案,例如已經壓縮過的第三方套件。ext 是檔案匯出後使用的副檔名。

接著加入其他任務的組態:

module.exports = function ( grunt ) {
	// Project configuration.
	grunt.initConfig( {
		pkg: grunt.file.readJSON( 'package.json' ),
		terser: {
			options: {
				mangle: {
					toplevel: true,
				},
			},
			build: {
				files: [
					{
						expand: true,
						src: [ 'js/*.js', '!js/*.min.js' ],
						ext: '.min.js',
					},
				],
			},
		},
		sass: {
			dist: {
				files: {
					'style.css': 'sass/style.scss',
				},
			},
		},
		autoprefixer: {
			your_target: {
				files: [
					{
						expand: true,
						src: [
							'style.css',
							'assets/css/*.css',
							'!**/*.min.css',
							'!assets/css/*.min.css',
						],
						ext: '.min.css',
					},
				],
			},
		},
		cssmin: {
			targets: {
				files: [
					{
						expand: true,
						src: [
							'style.css',
							'assets/css/*.css',
							'!**/*.min.css',
							'!assets/css/*.min.css',
						],
						ext: '.min.css',
					},
				],
			},
		},
	} );

	// Load the plugin that provides the "uglify" task.
	grunt.loadNpmTasks( 'grunt-terser' );
	grunt.loadNpmTasks( 'grunt-autoprefixer' );
	grunt.loadNpmTasks( 'grunt-contrib-sass' );
	grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
};

最後再利用 grunt.registerTask(); 安排任務順序:

module.exports = function ( grunt ) {
	// Project configuration.
	grunt.initConfig( {
		pkg: grunt.file.readJSON( 'package.json' ),
		terser: {
			options: {
				mangle: {
					toplevel: true,
				},
			},
			build: {
				files: [
					{
						expand: true,
						src: [ 'js/*.js', '!js/*.min.js' ],
						ext: '.min.js',
					},
				],
			},
		},
		sass: {
			dist: {
				files: {
					'style.css': 'sass/style.scss',
				},
			},
		},
		autoprefixer: {
			options: {},
			your_target: {
				files: [
					{
						expand: true,
						src: [
							'style.css',
							'assets/css/*.css',
							'!**/*.min.css',
							'!assets/css/*.min.css',
						],
						ext: '.min.css',
					},
				],
			},
		},
		cssmin: {
			options: {},
			targets: {
				files: [
					{
						expand: true,
						src: [
							'style.css',
							'assets/css/*.css',
							'!**/*.min.css',
							'!assets/css/*.min.css',
						],
						ext: '.min.css',
					},
				],
			},
		},
	} );

	// Load the plugin that provides the "uglify" task.
	grunt.loadNpmTasks( 'grunt-terser' );
	grunt.loadNpmTasks( 'grunt-autoprefixer' );
	grunt.loadNpmTasks( 'grunt-contrib-sass' );
	grunt.loadNpmTasks( 'grunt-contrib-cssmin' );

	// Default task(s).
	grunt.registerTask( 'default', [
		'terser',
		'sass',
		'autoprefixer',
		'cssmin',
	] );
};

最後,只要在終端機/命令提示字元中,執行 grunt 指令,接下來就會由 Grunt 執行剩下的任務工序。

結語

Grunt 在 Developer Roadmap 中並沒有被提到,但其中有提到類似概念的 Gulp。

透過 Grunt 的方法,可以將本來最小化 JavaScript 與 CSS 的工作變得更輕鬆。但是如果要真的將整個流程更有組織、更全面,看樣子還是需要多點一些 Webpack 的技能。

Sign up for our newsletter

Subscribe to our newsletter to receive the latest updates, expert insights, and practical tips directly in your inbox. Stay informed with content designed to help you grow.

+480.000 happy customers

Gain more with expert solutions

Unlock the full potential of your business with our expert solutions. Our team provides tailored strategies, professional guidance, and actionable insights to help you achieve better results.

  • Eric Chuang
  • •
  • 2025-01-23
如何同時使用 Webinoly 與 Cloudflare 保護網站安全

在社群夥伴勇哥的文章〈Webinoly 最新版快速安裝〉中,提到使用 Webinoly 來建立 WordPre […]

主機