Webpack 静态资源加载

Posted by Youzi Blog on October 11, 2019

前端 webpack 项目打包时,静态资源加载问题

backup: 项目脚手架为 vue-cli 2.x 版本,3.x 版本的配置文件不一样,后续有用到再补充。

起因

开发环境代码正常运行,各类资源加载正常,上到生产环境时,出现部分静态资源无法加载的问题,基本认为是 webpack 打包配置有问题,本文记录查找问题并修复的过程。

前提

服务器前端项目路径为/dist/...,访问路径为http://host:port/dist/#/...

配置文件

config -> index.js配置生产环境的对象中,即build,由于访问路径并没有配置为根目录,所以要将静态资源公共路径改为assetsPublicPath: './';特别地,如果访问路径为http://host:port/#/...,那么这里就设为根路径assetsPublicPath: '/',后面也没那么多有的没的配置了。片段代码如下:

1
2
3
4
5
6
7
8
build: {
  // Template for index.html
  index: path.resolve(__dirname, '../dist/index.html'),
  // Paths
  assetsRoot: path.resolve(__dirname, '../dist'),
  assetsSubDirectory: 'static',
  assetsPublicPath: './'
}

build -> webpack.base.conf.js解析目录的对象中,即resolvealias属性,添加一条staticPath: resolve('static'),注意这条信息指向的是代码根目录下的静态资源文件夹,这条主要是为了给js, vue里的一些路径信息提供便捷的引用方式,比如我们现在想引用static -> img -> bg-img.png,那么可以直接url('~staticPath/img/bg-img.png');片段代码如下:

1
2
3
4
5
6
7
8
9
10
resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
    vue$: 'vue/dist/vue.esm.js',
    '@': resolve('src'),
    '~': resolve('src/components'),
    utils: resolve('src/utils'),
    staticPath: resolve('static')
  }
},

backup: 事实上这条我感觉可以不用加,因为直接引用url(static/...)就可以了,还没试过,大概。。 backup 2: 上条不可以,我傻逼。

build -> utils.js找到针对vue-style-loader的配置,修改代码为以下:

1
2
3
4
5
6
7
8
9
if (options.extract) {
  return ExtractTextPlugin.extract({
    use: loaders,
    fallback: 'vue-style-loader',
    publicPath: '../../' // 添加了这一条
  });
} else {
  return ['vue-style-loader'].concat(loaders);
}

因为所有代码文件都会被编译成.js 和.css(取决于你用了哪个 loader),编译后的目录格式基本是

1
2
3
4
5
6
7
8
- dist
  - index.html
  - static
    - js
    - css
    - img
    - fonts
    ...

在运行生产代码的过程中,想要访问生产 static 文件下的资源,只能通过重写公共资源路径来实现。

比如编译后的代码放在了dist/static/css/sample.css,代码中访问了dist/static/img/bg.png,你在开发环境的代码肯定是以下两种形式:

1
2
3
4
url('/static/img/bg.png');
/* 使用根路径符号'/'来访问static */
url('~staticPath/img/bg.png');
/* 使用resolve方法来访问 */

如果用第一种,不管加不加publicPath,都会访问到根路径也就是http://host/,因为 webpack 并不会对绝对路径的 url 进行处理,但事实上你想访问的是http://host/dist/,这就会造成资源无法加载;而使用第二种,webpack 会对 url 进行二次封装,最终在生产环境中得到../../static/img/bg.png,这是正确的路径了,而且在开发环境中也能正确加载,在开发过程中,使用第一种是可以正确访问资源的,因为根目录就是项目代码所在的目录,但打包就 GG。

backup: 以上针对写在.vue文件下的<style></style>标签里的静态资源引用,因为脚手架模板自带了ExtractTextPlugin,这个插件可以把文件里的样式单独抽取出来形成.css文件。

原因

有些博客说这是 loader 的 bug 之类的,我认为不是的,是因为在配置时,将静态资源路径改成了相对当前目录路径./,而且因为访问路径不是根目录,所以不改又不行;相对路径是一种通用的路径,因为可能不确定服务器中生产代码到底放在了哪一级或者哪几级目录下,比如可能放在/dist || /path/path2/path3/dist都有可能,所以使用了相对路径,针对这种情况,就需要用上述的方法修改publicPath的方法,其实后面跟的路径也可以是/dist/ || /path/path2/path3/dist,因为就是要让资源的 url 拼接成对应的文件夹路径;

后来又想到,如果直接把静态资源路径改成服务器实际访问的路径呢,比如assetsPublicPath: '/dist/',试了一下,是可行的,前提是根路径就是 dist,如果也是嵌套多层的,那就把前面的路径都添加上去;使用这种方法就不用修改publicPath了,但是也要注意需要在build -> webpack.base.conf.js -> resolve -> alias下添加一条staticPath: resolve('static'),毕竟 webpack 不会二次封装根路径。

总结

总的来说,最重要的还是要分析打包后的文件,看看资源的路径到底改了没有,被改成什么样了,熟悉 webpack 对哪些 url 进行封装。

参考:https://github.com/vuejs-templates/webpack/issues/166