前端自动化grunt
grunt是什么?
grunt是一个非常好的自动化工具,你只管codeing,它会自动帮你将代码合并(concat)、压缩(uglify)、语法检查(jshint)、自动编译less(contrib-less)和sass(contrib-sass)、压缩图片(contrib-imagemin)、读写拷贝移动文件等等,极大地简化了你的工作,它有很多插件
Grunt 常用插件
Js 文件校验:grunt-contrib-jshint
文件拷贝:grunt-contrib-copy
文件删除:grunt-contrib-clean
文件合并:grunt-contrib-concat
Sass 解析:grunt-contrib-sass
Css 压缩:grunt-contrib-cssmin
Html 压缩:grunt-contrib-htmlmin
Js 压缩混淆:grunt-contrib-uglify
静态资源文件模版:grunt-usemin
静态资源文件版本:grunt-rev
任务运行时间插件:time-grunt
加载 Grunt 插件:load-grunt-tasks
自动添加样式前缀:grunt-autoprefixer
...
npm install grunt-contrib-watch --save-dev 安装时候顺带添加到devDependencies 中
执行任务方式eg: grunt copy:dist
eg: https://github.com/WorldWideTelescope/wwt-web-client
// Copyright 2020 the .NET Foundation
// Licensed under the MIT License
module.exports = function (grunt) {
'use strict';
// Force use of Unix newlines
grunt.util.linefeed = '\n';
RegExp.quote = function (string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
};
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
client: {
files: ['*.html','views/**/*', 'css/*', 'ext/*', 'controllers/**/*', 'factories/*', 'images/*'], //需要监听的文件
options: {
livereload: true
},
tasks: [
'uglify:webclient',
'less:compileCore',
'cssmin:minifyCore',
'template:indexhtml','copy:dist',]
}
},
banner: '/**\n' +
'* AAS WorldWide Telescope Web Client\n' +
'* Copyright 2014-2020 .NET Foundation\n' +
'* Licensed under the MIT License\n' +
'* Git hash <%= gitinfo.local.branch.current.SHA %>\n' +
'**/\n',
// Triger the loading of the Git version info
gitinfo: {},
// Different build profiles. The "localtest" file is in .gitignore and is
// intended to be used for temporary local testing. The other profiles are
// in Git for reproducibility.
profile: {
dev: 'profile-dev.yml',
localtest: 'profile-localtest.yml',
prod: 'profile-prod.yml',
testing: 'profile-testing.yml',
},
// Task configuration.
concat: {
options: {
banner: '<%= banner %>',
process: function(src, filepath) {
if (filepath == 'app.js' || filepath == 'index.html') {
return grunt.template.process(src);
} else {
return src;
}
},
},
webclient: {
src: [
'ext/intro.js',
'ext/angular-intro.js',
'app.js',
'directives/ContextMenu.js',
'directives/CopyToClipboard.js',
'directives/Localize.js',
'directives/Scroll.js',
'directives/editslidevalues.js',
'directives/movable.js',
'factories/AppState.js',
'factories/AutohidePanels.js',
'factories/FinderScope.js',
'factories/HashManager.js',
'factories/Localization.js',
'factories/MediaFile.js',
'factories/SearchUtil.js',
'factories/Skyball.js',
'factories/ThumbList.js',
'factories/UILibrary.js',
'factories/Util.js',
'dataproxy/Astrometry.js',
'dataproxy/Community.js',
'dataproxy/Places.js',
'dataproxy/SearchData.js',
'dataproxy/Tours.js',
'controllers/ContextPanelController.js',
'controllers/IntroController.js',
'controllers/LayerManagerController.js',
'controllers/LoginController.js',
'controllers/MainController.js',
'controllers/MobileNavController.js',
'controllers/modals/ColorPickerController.js',
'controllers/modals/DataVizController.js',
'controllers/modals/EmbedController.js',
'controllers/modals/GreatCircleController.js',
'controllers/modals/ObservingLocationController.js',
'controllers/modals/ObservingTimeController.js',
'controllers/modals/OpenItemController.js',
'controllers/modals/ShareController.js',
'controllers/modals/SlideSelectionController.js',
'controllers/modals/TourSlideText.js',
'controllers/modals/VOTableViewerController.js',
'controllers/modals/VoConeSearchController.js',
'controllers/modals/refFrameController.js',
'controllers/tabs/CommunityController.js',
'controllers/tabs/CurrentTourController.js',
'controllers/tabs/ExploreController.js',
'controllers/tabs/SearchController.js',
'controllers/tabs/SettingsController.js',
'controllers/tabs/ToursController.js',
'controllers/tabs/ViewController.js',
'misc/move.js',
'misc/util.js'
],
dest: 'dist/wwtwebclient.js',
nonull: true,
}
},
uglify: {
options: {
mangle: false,
preserveComments: 'some',
banner: '<%= banner %>'
},
webclient: {
src: '<%= concat.webclient.dest %>',
dest: 'dist/wwtwebclient.min.js'
},
},
less: {
compileCore: {
options: {
strictMath: true,
sourceMap: true,
outputSourceFiles: true,
sourceMapURL: 'webclient.css.map',
sourceMapFilename: 'dist/css/webclient.css.map'
},
src: 'css/webclient.less',
dest: 'dist/css/webclient.css'
}
},
autoprefixer: {
options: {
browsers: [
"Android 2.3",
"Android >= 4",
"Chrome >= 20",
"Firefox >= 24",
"Explorer >= 10",
"iOS >= 6",
"Opera >= 12",
"Safari >= 6"
]
},
core: {
options: {
map: true
},
src: '<%= less.compileCore.dest %>'
}
},
cssmin: {
options: {
compatibility: 'ie10',
keepSpecialComments: '*',
noAdvanced: true
},
minifyCore: {
src: '<%= autoprefixer.core.src %>',
dest: 'dist/css/webclient.min.css'
}
},
template: {
options: {
data: function() {
var d = require('lodash').clone(grunt.config.get('profile_data'));
d.shortSHA = grunt.config.get('gitinfo.local.branch.current.shortSHA');
return d;
}
},
indexhtml: {
files: {
'dist/index.html': 'index.html'
}
}
},
copy: {
dist: {
files: [
{
expand: false,
src: [
'assets/*',
'css/introjs.css',
'css/angular-motion.css',
'css/mcecontent.css',
'css/skin.min.css',
'default.aspx',
'favicon.ico'
],
dest: 'dist/'
},
{
expand: true,
src: [
'fonts/*',
'images/*',
'views/**'
],
dest: 'dist/',
filter: 'isFile'
}
]
}
}
});
require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});
// 加载插件
grunt.loadNpmTasks('grunt-contrib-watch');
// 自定义任务
grunt.registerTask('live', ['watch','profile:dev']);
grunt.registerMultiTask('profile', 'Specify the build profile', function() {
var data = grunt.file.readYAML(this.data);
grunt.config.set('profile_data', data);
});
var all_tasks = [
'gitinfo',
'concat:webclient',
'uglify:webclient',
'less:compileCore',
'autoprefixer:core',
'cssmin:minifyCore',
'template:indexhtml',
'copy:dist'
];
for (let profname of ['dev', 'localtest', 'prod', 'testing']) {
grunt.registerTask('dist-' + profname, ['profile:' + profname].concat(all_tasks));
}
};
执行 grunt live 就会启动监听,然后有修改,就会执行对应tasks
- grunt live --force 跳过中间warn 错误。停止问题
- pnpm grunt live --force // 中间require 引包问题
- 环境变量 还有点问题 profile 默认加载进来
package.json 参考
"buildConfig": {
"uglify": true
},
"description": "AAS WorldWide Telescope web client",
"devDependencies": {
"connect-livereload": "^0.6.1",
"grunt": "^1.6.1",
"grunt-autoprefixer": "^3.0",
"grunt-banner": "^0.6",
"grunt-contrib-concat": "^1.0",
"grunt-contrib-copy": "^1.0",
"grunt-contrib-cssmin": "^3.0",
"grunt-contrib-less": "^2.0",
"grunt-contrib-uglify": "^4.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-gitinfo": "^0.1",
"grunt-template": "^1.0",
"load-grunt-tasks": "^5.0",
"tslib": "^1.10.0"
},