0%

使用webpack构建AngularJs项目:从requireJs迁移到webpack

前面的三篇文章分别为:起步支持es6加载资源,我们现在可以完整的进行一个项目了。但我们从刚开始的目的就是探索这个过程,然后达到将项目中的requireJs加载更改为webpack加载。现在来看下如何来替换。

多入口设置

目前这个项目是基于多入口的,在项目目录下有个index.html来做初始页面的跳转,然后分别有xx/a.htmlxx/b.html分别进入对应的页面,然后进入路由后才是angularJs的单页面应用模式,也就是说,我访问到某一个angularJs路由为:xx/a.html#/test/tt。针对于这种情况,我们webpack需要做对应的多入口处理。

修改webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module.exports = {
entry: {
login: './src/login/login.js',
index: './src/index.js',
'app-uc': './src/app-uc/js/main.js',
vendor: Object.keys(packageJson.dependencies),
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: "index.html",
template: "src/index.html",
inject: "body",
chunks: ['index'],
}),
new HtmlWebpackPlugin({
filename: "login/login.html",
template: "src/login/login.html",
inject: "body",
chunks: ['login'],
}),
new HtmlWebpackPlugin({
filename: "app-uc/forgetPassword.html",
template: "src/app-uc/forgetPassword.html",
inject: "body",
chunks: ['app-uc'],
}),
],
}

每个入口有对应的html文件和入口js文件。通过HtmlWebpackPlugin以对应入口html为模板,生成到dist目录下的html,并通过chunks参数来引入对应的包。

requireJs -> webpack

关于requireJs的用法,可以参考阮一峰的博客:Javascript模块化编程(三):require.js的用法

我们看下项目里面的requireJs的用法。

首先在入口的html文件中最下面有一条:

1
<script src="../node_modules/requirejs/require.js" data-main="js/main"></script>

这个data-main=“js/main"表示的是在html加载好后加载js/main.js文件。然后看下js/main.js文件内部是啥哈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require.config({
urlArgs: "==version==",
waitSeconds: 0,
paths: {
'baiduMap': 'https://api.map.baidu.com/getscript?v=2.0&ak=eMekSXxqG1j2wLM57RFN61l8T6eB1EDx&services=',

'ace': '../../node_modules/ace-builds/src',
'angular': '../../node_',
},
shim: {
'angular': {
exports: 'angular',
deps: ['jquery']
},
}
});
require([
'app',
'routes',
], function(app, config){
// 项目启动后的逻辑
})

main.js中的require([], funciont(){})表示了依赖的模块,默认会去找当前js文件目录同级的文件,比如这里的app其实就是去找js/app.js文件。而require.config()文件定义了名称的路径,以及不支持AMD规范的第三方库可以使用shim来定义他们的特征。

我们直接修改为:

1
2
3
4
5
6
7
8
9
10
11
import angular from 'angular';
import $ from 'jquery';
import config from './routes';
app.config([
'$routeProvider',
function ($routeProvider) {
// angularjs 相关操作
}
]);
// 引导启动angular
angular.bootstrap(document, ['app']);

然后去修改对应js文件,有依赖第三方库的直接import,有依赖其他js文件的也直接import

比如routes.js文件,之前是:

1
2
3
4
5
6
7
8
9
10
11
12
define([], function() {
return {
defaultRoutePath: '',
routes: {
'/register': {
templateUrl: 'partials/register.html',
controller: 'registerCtr',
dependencies: ['js/controllers/approve-ctrl.js']
},
}
}
})

修改后:

1
2
3
4
5
6
7
8
9
10
export default {
defaultRoutePath: '',
routes: {
'/register': {
templateUrl: 'partials/register.html',
controller: 'registerCtr',
dependencies: ['js/controllers/approve-ctrl.js']
},
}
}

其他的controller和service文件基本都类似,修正下define函数即可,然后将需要的依赖引入即可。

费时间的问题

在迁移过程出现了一个很头疼的问题,angularJs这个项目中在入口文件的main.js定义了模块:

1
2
3
4
5
const app = angular.module('app', [
'ngAnimate',
'ngRoute',
'services',
])

然后相关的services在文件加载的时候也放入了一个模块:

1
var services = angular.module('services', ['ngResource']);

然后盯了好半天也不知道他们怎么进行关联的。

还是angularJs生疏了,其实在angular.module('app', ['ngRoute', 'services'])的时候就已经将services当成一个特性模块注入了。这就好比angular里面的shareModule,一个模块可以被注入到其他模块中。只是angularJs这里是字符串的定义方式,没明白过来,也是蠢哭了。。。

css分离

目前我们css是在js中引用的,导致打包的时候css被填充到了js文件里面。刷新页面的时候会很尴尬的看到dom先出来了,加载好js后才会应用样式,会有短暂的没样式的时间。

我们使用mini-css-extract-plugin插件来分离css文件,安装:

1
$ yarn add mini-css-extract-plugin -D

修改webpack.config.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
]
}
]
}
plugins: [
new MiniCssExtractPlugin(),
],
}

再打包查看,css被独打包为独立的问题,并放在html文件的head标签中。

然后发现css是没被压缩的,打包为线上环境是需要压缩的,我们使用css-minimizer-webpack-plugin插件,先安装:

1
$ yarn add css-minimizer-webpack-plugin -D

然后修改webpack.config.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
optimization: {
splitChunks: { },
minimize: true,
minimizer: [
new CssMinimizerPlugin({
minify: [CssMinimizerPlugin.cleanCssMinify, CssMinimizerPlugin.cssoMinify],
minimizerOptions:[
{ compatibility: 'ie11,-properties.merging' },
{ restructure: false },
]
}),
],
},
}

这个是生产环境的打开压缩,开发环境中为了热加载还是不要压缩了。


到这里基本改造完成了,后续只需要将项目中requireJs逐步换到webpack即可,时间问题。

其实走到这里,核心的地方就是angularJs的依赖注入处理,其他的都是webpack相关的知识,这样走一遍还是很有裨益的。

码字辛苦,打赏个咖啡☕️可好?💘