0%

使用webpack构建AngularJs项目:加载资源

接上一篇 使用webpack构建AngularJs项目:支持ES6 我们已经将js的加载和转换处理好了,现在来看下资源的加载以及样式的处理。

加载资源

我们项目中会有一些图片展示在页面中,资源的使用有三种方式:

  • 在js中import,然后作为变量直接在模板中使用
  • 在html中,直接使用src的资源路径引用
  • 在css中,使用background之类的资源url引用

webpack5里面集成了资源模块(asset module),无需配置额外loader。资源模块类型(asset module type)有四种:

  • asset/resource 发送一个单独的文件并导出URL(对应之前的file-loader
  • asset/inline 导出一个资源的dataURI(对应之前的url-loader
  • asset/source 导出资源的源代码(对应之前的row-loader
  • asset 在导出一个dataURI和发送一个单独文件之间自动选择(对应之前的url-loader并配置资源体积实现)

我们首先创建项目的资源文件夹src/assets

1
$ mkdir src/assets

然后随便放一张图片,我这里图片路径是:src/assets/qin.png。ps:原神中的角色”琴“团长~

然后我们先在login页面中使用:

  • src/login/login.controller.js中引用:

    1
    2
    3
    4
    5
    6
    import qinImage from '/src/assets/qin.png';

    function loginController($scope, httpService) {
    "ngInject";
    $scope.qinImage = qinImage;
    }
  • src/login/login.lazy.html中使用:
1
<img ng-src="{{qinImage}}"/>

发现是加载不到的,需要去修改webpack.config.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
output: {
assetModuleFilename: "assets/[hash][ext][query]",
},
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset',
}
]
}
}

这样,资源文件就会自动的在resouceinline之间选择:小于8kb的文件会视为inline模块类型,否则会直接视为resource模块类型。可以在Rule.parser.dataUrlCondition.maxSize里面进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
// 设置文件的阈值为4kb。
maxsize: 4 * 1024,
}
}
}
]
}

然后重新运行yarn start,可以在login路由正常看到引用的图片。

再尝试下直接用html的方式,在src/login/login.html中增加一条图片:

1
2
3
4
5
6
<div class="login">
<p>login page</p>
<img ng-src="{{qinImage}}"/>
<img src="/src/assets/qin.png"/>
{{name}}
</div>

我们会发现,第一个img标签是会显示图片的,但是第二条是显示不出来的。

回想下,我们的html文件的打包方式是两种:

  • 直接放在js文件中,是html-loader处理的。
  • 懒加载*.lazy.html,是file-loader处理的。

那我们看下直接使用html-loader加载的模板里面可以直接用路由的方式吗?

我们修改home路由的模板为文件加载的方式,创建src/home/home.htmlsrc/home/home.controller.js

1
2
3
$ mkdir src/home
$ touch src/home/home.html
$ touch src/home/home.controller.js

编辑src/home.home.html

1
2
3
4
5
<div>
<p>home page</p>
<p>{{title}}</p>
<img src="/src/assets/qin.png"/>
</div>

编辑src/home/home.controller.js

1
2
3
4
5
6
7
8
9
10
11
import homeTemplate from './index.html';

homeController.$inject = ['$scope'];
function homeController($scope) {
$scope.title = 'home'
}

export default {
homeTemplate,
homeController,
}

然后修改src/index.js

1
2
3
4
5
6
7
8
9
import home from './home/home.controller';
app.config(($httpProvider, $routeProvider, $locationProvider, $controllerProvider) => {
$routeProvider
.when('/', {
controller: 'homeCtrl',
template: home.homeTemplate,
})
});
app.controller('homeCtrl', home.homeController)

然后重新运行,我们可以看到home路由下图片是可以正常显示的,这是为啥?🤔

先打包下,看下打包后的内容是怎样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var code = "<div> <p>home page</p> <p>{{title}}</p> <img src=\"" + ___HTML_LOADER_REPLACEMENT_0___ + "\"/> </div> ";
var ___HTML_LOADER_REPLACEMENT_0___ = _node_modules_html_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_0___default()(___HTML_LOADER_IMPORT_0___);
/* harmony import */
var _node_modules_html_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/html-loader/dist/runtime/getUrl.js */ "./node_modules/html-loader/dist/runtime/getUrl.js");
/* harmony import */
var _node_modules_html_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_html_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_0__);
// Imports
var ___HTML_LOADER_IMPORT_0___ = new URL(/* asset import */ __webpack_require__(/*! ../../../../src/assets/qin.png */ "./src/assets/qin.png"), __webpack_require__.b);

/***/ "./src/assets/qin.png":
/*!****************************!*\
!*** ./src/assets/qin.png ***!
\****************************/
/***/
((module, __unused_webpack_exports, __webpack_require__) => {

module.exports = __webpack_require__.p + "assets/47f5e9bfe5b82ca1ef05.png";
})

可以看到,使用html-loader加载的模板文件是解析了的然后嵌入到了js文件中,并且文件路径被替换到了打包后的资源文件,所以是可以找到的。

在看下通过file-loader懒加载的文件,里面的img.src路径是没被转换的,所以是找不到这个路径的。

那该如何解决?

暂不解决了 🤣

这个懒加载html的需求就是个假需求!我们顶多是懒加载一个模块,而不是懒加载一个html!

处理css

需要使用style-loadercss-loader,首先安装:

1
$ yarn add style-loader css-loader -D

如果正式环境的话我们希望压缩css,需要用到mini-css-extract-plugin插件:

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
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
]
}
]
},
}

然后我们在项目中使用css文件的时候,本来的写法是在html中link标签引用的,我们需要改成在js文件中即可:

1
import 'xxx/index.css';

然后css中的文件需要从项目的根目录引导:

1
background: url('/src/assets/xxx.jpg');

查看打包的文件,样式文件被放入了js中,暂时是没什么问题。

将第三方库暴露给全局

项目中使用了jquery,我们希望可以使用全局的$符号,这样更方便,可以采用expose-loader将一些库暴露给全局,可以通过window.$之类的方式直接调用。

安装expose-loader

1
$ yarn add expose-loader -D

编辑webpack.config.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
module: {
rules: [
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
expose: ['$', 'jQuery'],
}
},
]
},
}

加载字体文件

有些css样式中是会引用.ttf之类的字体文件的,我们需要加上字体文件的处理。

直接更新webpack.config.js

1
2
3
4
5
6
7
8
9
10
module.exports = {
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
]
},
}

这样直接把字体文件会编译到dist/assets文件夹中。

json资源文件

项目中有些本地的json资源,通过http的get直接调用前端的路径。这种我们需要将它们挪到dist目录中,而且需要保持路径。

需要安装copy-webpack-plugin

1
$ yarn add copy-webpack-plugin -D

然后修改webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from:path.resolve(__dirname, 'src/xx/jsonDir'),
to: path.resolve(__dirname, 'dist', 'xx/jsonDir'),
}
]
})
],
}

基本流程到这里已经差不多了,主要是angualr的注入,其他的都是webpack的基本操作。

接下来就是将项目的requireJs转移为webpack。💪

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