目录
vue-cli@2项目通过修改index.html引用路径或添加配置信息
方案二:修改项目的assetsPublicPath或添加publicPath配置信息
vue-cli@3项目通过修改index.html引用路径或添加配置信息
场景描述
通过vue-cli创建的vue项目,npm run serve
运行开发环境可以看到效果,但是执行 npm run bulid
本地打包之后生成的dist文件下的index.html用浏览器无法直接打开,显示空白页,控制台有很多报错信息如下:GET file:///...... net::ERR_FILE_NOT_FOUND(vue-cli3创建vue项目)或是 Failed to load resource: net::ERR_FILE_NOT_FOUND(vue-cli2创建vue项目)
问题分析
可能有人会问,为什么打包后的dist文件夹里inde.html,在本地直接打开无法访问,要放在服务器的根目录才能打开,如何才能像访问 npm run dev(使用vue-cli2创建的vue项目的启动方式)或npm run serve(使用vue-cli3创建的vue项目的启动方式) 的地址那样访问?
首先,我们来解释一下vue脚手架项目启动项目的原理,其实,在你使用 npm run dev或npm run serve的时候,实际是临时创建了一个webpack-dev-server或vue-cli-service serve的node服务器,为了方面后面的 hot-reload(热重载)的需求,必须所有的更新都要在服务上处理后进行更新,如果你是单纯用file协议打开静态网站的方式,是没有办法做到这个处理的,如果可以,也是需要编译和重载的,成本很高昂。所以,vue通过npm run dev或npm run serve启动项目,也是以启动服务器的方式进行编译的。
我们之所以出现报错,这是因为打包的dist文件夹是需要放在服务器上运行的,资源默认放在根目录下。你打开index.html就可以发现,被打包成的css和js文件的引用使用的是绝对路径,例如: <link href="/css/app.8acb2246.css" rel="stylesheet">、<script src="/js/chunk-vendors.da145e16.js"></script>,但对本地磁盘来说," / " 指向的是磁盘根目录,所以,找不到引用的文件。因为当我们在本地使用file协议打开index.html是需要引用相对路径的静态资源。一句话来说,就是打包以后的index.html文件中的引用路径不对,才导致报错
解决方案
这里会介绍使用 vue-cil@2 和 vue-cil@3 两种方式创建vue项目的解决方案
有以下3种解决方案
方案一:将index.html中引用的绝对路径改为相对路径
方案二:修改或是添加项目的配置信息,实现本地访问
方案三:通过搭建本地服务器,实现本地访问(3种方法)
vue-cli@2项目通过修改index.html引用路径或添加配置信息
有3种实现方案,推荐第二种方案!
方案一:将index.html中引用的绝对路径改为相对路径
可以选择手动将index.html中所有引用资源的地方全部改成相对路径,例如:
<script type=text/javascript src=static/js/manifest.2ae2e69a05c33dfc65f8.js></script>
<script type=text/javascript src=static/js/vendor.5d4fc21e9bad685c9b37.js></script>
<script type=text/javascript src=static/js/app.394b37fa387958cd2f69.js></script>
方案二:修改项目的assetsPublicPath或添加publicPath配置信息
当然,更优雅的做法是修改项目的assetsPublicPath或添加publicPath配置信息,有3种方法,推荐第3种,如下:
1、修改config/index.js中build对象的assetsPublicPath,改为当前目录(./),而不是根目录(/);
module.exports = {
...
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
// 修改前
// assetsPublicPath: '/',
// 修改后:assetsPublicPath改为当前目录./
assetsPublicPath: './',
...
}
}
2、修改build/webpack.base.conf.js中的publicPath,在build/webpack.prod.conf.js添加publicPath
* build/webpack.base.conf.js文件
output: {
path: config.build.assetsRoot,
filename: '[name].js',
// 修改前
// publicPath: process.env.NODE_ENV === 'production'
// ? config.build.assetsPublicPath
// : config.dev.assetsPublicPath
// 修改后
publicPath: process.env.NODE_ENV === 'production'
? './' + config.build.assetsPublicPath
: './' + config.dev.assetsPublicPath
},
* build/webpack.prod.conf.js文件
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
// 修改前
// output: {
// path: config.build.assetsRoot,
// filename: utils.assetsPath('js/[name].[chunkhash].js'),
// chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
// },
// 修改后
output: {
publicPath: './', // 添加的一行
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
3、在 webpack.prod.conf.js 中的 output 对象添加参数publicPath:'./ '
具体代码如下:
const webpackConfig = merge(baseWebpackConfig, {
...
output: {
publicPath: process.env.NODE_ENV === 'production'
? './' +config.build.assetsPublicPath
: './' + config.dev.assetsPublicPath,
// 上面是添加代码
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
...
})
以上方案一、二,都可以解决,此时再运行npm run build打包后,打开dist / index.html发现所有资源的引用路径已经变为相对路径了,此时可以双击index.html在浏览器中正常访问了!
vue-cli@3项目通过修改index.html引用路径或添加配置信息
有2种实现方案,推荐第二种方案!
方案一:将index.html中引用的绝对路径改为相对路径
例如:
<link href="js/chunk-vendors.da145e16.js" rel="preload" as="script">
<link href="css/app.8acb2246.css" rel="stylesheet">
<script src="js/chunk-vendors.da145e16.js"></script>
<script src="js/app.1102999b.js"></script>
方案二:修改项目的publicPath配置信息在本地访问
当然,更优雅的做法是修改项目的publicPath配置信息,如下
1、在项目根目录新建 vue.config.js
文件,并添加publicPath: './ '
// vue.config.js
module.exports = {
publicPath: './'
}
2、然后,关键的一步,在 src/router.js
中删去 mode: 'history'
...
export default new Router({
// mode: 'history', // 有这句的删掉,没有就不用管,因为默认mode: 'hash'模式
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
}
]
})
现在再次执行npm run build重新打包后,打开 dist下的 index.html就可以正常访问了
👉 番外:页面可以正常打开了,但是页面上的一些图片请求失败,怎么办
解决办法:在build/utils.js中,如下位置,添加 publicPath: '../../'
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: "vue-style-loader",
publicPath: "../../"
});
}
👉 番外:页面可以正常打开了,如果vue-router跳转路由页面无法显示
解决方法:打开index.js看路由配置,mode:' hash ' 改这个配置即可:
//VueRouter's setting
export const router = new VueRouter({
base: "/",
mode: "hash",
routes
});
参考链接:解决Vue项目打包后打开index.html页面显示空白以及图片路径错误的问题
vue-cli@2/3项目通过搭建本地服务器,实现本地访问
有3种搭建本地服务器实现方案,推荐第2种方案!
方案一、使用http-server静态服务器
http-server
是一个简单的、零配置的命令行静态 HTTP 服务器。它足够强大,可以用于生产用途,但它足够简单且可破解,可用于测试、本地开发和学习。
用法查看官网:http-server - npm
http-server是一个基于命令行的简单的静态HTTP服务器,使用方法很简单:
① 安装
npm install http-server -g
② 进入dist文件夹
cd dist
③ 执行命令
http-server
大功告成!可以打开浏览器在localhost:8080中查看了。
方案二、通过在dist目录中起服务访问
使用express框架,搭建一个简单的nodejs服务器
step1:在dist 路径下,安装express包
npm install express
step2:在dist文件中添加服务器app.js文件
var express = require("express");
var app = express();
const hostname = "localhost";
const port = 8080;
// Express 提供了内置的中间件 express.static 来设置静态文件
app.use(express.static("./"));
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}`);
});
step 3:命令行或是在终端运行
node app.js
方案三、使用http模块,手写node服务器
使用http模块只需要在文件中通过require(“http”) 引入即可。http模块是node.js原生模块中最为亮眼的模块。传统的HTTP服务器都会由nginx之类的软件来担任,但是node.js不需要。node.js的http模块本身就可以构建服务器,而且性能非常可靠。
◼️ 了解http模块:Node学习HTTP模块(HTTP 服务器与客户端) | Node.js核心模块—http模块应用
我们可以使用nodejs原生的http模块,创建web服务器,在dist同级目录中新增文件server.js
// server.js
// 1. 引入接下来要用到的node内置模块
const http = require("http");
const url = require("url");
const path = require("path");
const fs = require("fs");
// 2. 利用path解析当前目录,然后拼接dist目录,使得服务器当前的根目录变为dist
const root = path.join(path.resolve(process.argv[2] || "."), "dist");
// 3. 创建http服务器
const server = http.createServer((request, response) => {
// 4. 解析请求url获取文件路径
const pathname = url.parse(request.url).pathname;
const filepath = path.join(root, pathname);
// 5. 使用fs文件系统模块读取index.html文件并返回给前端
fs.stat(filepath, (err, stats) => {
if (!err && stats.isFile()) {
// 响应头设为200
response.writeHead(200);
// 创建一个读写流管道,将index.html文件内容写入response并返回
fs.createReadStream(filepath).pipe(response);
} else {
// 请求路径不对时返回404
response.writeHead(404);
response.end("404 Not Found");
}
});
});
// 6. 服务器监听8080端口
server.listen(8080);
命令行定位到app.js同级目录中执行node app.js
,此时,在浏览器中可以访问http://localhost:8080/index.html
查看效果。
参考资料