使用webpack替换grunt
由于一直维护的项目打包是基于grunt的,虽然自己已经实现了grunt下代理和es6等功能,但是为了让老项目更现代化些,预将webpack替换掉grunt。
配置webpack
entry
首先第一步先配置基础的webpack配置,grunt的入口是html,而代码中并没有使用import/export,所以我们需要手动将所有js添加到entry中。按js作用和类型我分成了vendor,controllers、services等。毕竟分包减小单个js文件体积以提升效率。
为了避免以后每次增加一个js就要改entry,使用了glob做文件遍历。如:
{
// ...
entry: {
other: [/** 配置的js */],
app: [
...glob.sync('./app/scripts/filters/**/*.js'),
...glob.sync('./app/scripts/directives/**/*.js'),
// ...
],
controller: [
...glob.sync('./app/scripts/controllers/**/*.js'),
]
// ...
}
// ...
}rules
下面就要配置loader了,js、css、less、scss这些都是用正常的通用配置。
其中需要注意的是处理html(index.html, main.html,以及views下的各个按需加载的页面)的时,一开始使用的是html-loader,由于它无法处理img上的srcset属性,所以使用了html-srcsets-loader。
<img src="/images/qiye_logo.png" class="f-margin-top-5" srcset="/images/qiye_logo@2x.png 2x" alt="网易合作伙伴平台" />{
test: /\.html$/i,
use: [{
loader: 'html-srcsets-loader',
options: {
attrs: ['img:src', ':srcset'],
minimize: true,
removeComments: true
}
}]
}plugins
我们需要使用html-webpack-plugin插件来处理所有的html文件。包括主页面和各个按需引入的页面。同样的,为了提升使用体验我们可以用glob曲循环变量html页面的方式配置。
const files = glob.sync("./app/views/**/*.html");
files.forEach((pa) => {
let opt = Object.assign({}, defaults);
// ... 处理
arr.push(new HtmlWebpackPlugin(opt));
});由于项目中使用了jQuery,做一个全局的变量:
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
})需要注意,我们需在angularjs之前先绑定jQuery。可在angularjs源码的bindJQuery方法中看到, 不然angular.element就是angularjs内置的jQLite了(jQuery子集,有jq的基本功能)
// bind to jQuery if present;
jQuery = window.jQuery;
// Use jQuery if it exists with proper functionality, otherwise default to us.由于项目按需加载views下的页面,get请求会被浏览器缓存,所以需要加一个query参数防止,使用了DefinePlugin做变量替换。
new webpack.DefinePlugin({
__auto_html_version: (new Date()).valueOf() + '',
}),多页面配置
由于项目是多页面的,所以需要借助html-webpack-plugin配置多页面。
new HtmlWebpackPlugin({
template: path.join(__dirname, '../app/index.html'),
minify: true,
inject: true,
filename: 'index.html',
chunks:['other', 'access']
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, '../app/main.html'),
minify: true,
inject: true,
filename: 'main.html',
chunks:['other', 'app', 'services']
}),去除html处理
使用一段时间发现,热更新和打包都比较有点慢。而views目录下的html仅有部分需要处理图片,所以将图片使用import方式引入,挂载到$scope下。
整个views文件夹用copy-webpack-plugin拷贝,节省差不多30s左右的打包时间 。当然这会导致用户加载html时间略微变长。
其他修改
dev
webpack的特殊配置基本OK了,其他都是一些常规的,如dev下配置一些webpack-dev-server的配置,mini-css-extract-plugin插件等等。
可以使用hard-source-webpack-plugin插件加快热更新和以后的打包速度,热更新可以从十几秒优化到1s内。
prod
build情况下,可能还需要加些optimization的配置,对node_modules下的第三方依赖做个拆分。
第三方依赖
将所有第三方插件用npm的方式安装,并且在主js文件(第一个执行的js文件)以import的方式引入。注意对应的版本号,尽量使用相同的版本号,后期等稳定后再升级。
第三方依赖的样式文件也同样需要引入。项目是机遇Angularjs的,大致如下:
import angular from 'angular';
import ngAnimate from 'angular-animate';
import ngAria from 'angular-aria';
import ngCookies from 'angular-cookies';
import ngMessages from 'angular-messages';
import ngResource from 'angular-resource';
import ngRoute from 'angular-route';
import ngSanitize from 'angular-sanitize';
import angularLoadingBar from 'angular-loading-bar';
import uibs from 'angular-ui-bootstrap';
import toastr from 'angular-toastr';
import uiSelect from 'ui-select';
import JSZip from 'jszip';
import Clipboard from 'clipboard';
import _ from 'lodash';
// import ngEcharts from 'angular-echarts';
import 'angular-translate';
import 'angular-translate-loader-static-files';
import moment from 'moment';
import * as echarts from 'echarts';有些如翻译的只要直接impot就行了。接下来是替换angular的module初始化中的配置,原先是字符串,现在需要使用对象。大致如下:
var app =
angular
.module('adminApp', [
ngAnimate,
ngAria,
ngCookies,
ngMessages,
ngResource,
ngRoute,
ngSanitize,
'pascalprecht.translate',
uibs,
uiSelect,
// 'ui.bootstrap',
toastr,
angularLoadingBar,
// 'TreeView',
'angular-echarts',
'ng.shims.placeholder'
])部分依赖需要绑定到window下,如echarts,mmoment这种需要import来,挂到window下。因为老项目中,都是直接使用的这些变量。
window.moment = moment;
window.echarts = echarts;
window.Clipboard = Clipboard;
window.JSZip = JSZip;
window._ = _;最后,angular.module中返回值也需要绑定到window下,其他老模块会使用到。
window.app = app; // 老文件用这样就可以了。