Nuxt spa deploy
参考 https://nuxtjs.org/guide/commands/#single-page-application-deployment-spa-
SSR模式虽然有很好的SEO支持【服务端预渲染】,但是由于我们网站的内容是基于实时API,部分也基于user authentication的,所以采用SPA方式发布。 大部分内容都是固定的,只是数据来源是API获取。采用SSR模式,并且开始https支持。
参考 https://nuxtjs.org/guide/commands#server-side-rendered-deployment-universal-ssr-
To deploy, instead of running nuxt, you probably want to build ahead of time. Therefore, building and starting are separate commands:
nuxt build nuxt start
You can also set server.https in your nuxt.config.js with the same set of options passed to https.createServer, should you choose to serve Nuxt.js in HTTPS mode. Unix sockets are also available if you set the server.socket option in nuxt.config.js (or -n in the CLI). When using Unix sockets, make sure not to set the host and port parameters otherwise the socket parameter is ignored.The package.json like follows is recommended:
{ "name": "my-app", "dependencies": { "nuxt": "latest" }, "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start" } }开发的时候其实就已经会有上面的配置了:
Note: we recommend putting .nuxt in .npmignore or .gitignore.默认 .nuxt文件夹就存在,.gitignore在git 使用之后也是存在的,.npmignore参考官方声明,如果有.gitignore了可以直接在其中添加 ,具体参考 https://docs.npmjs.com/using-npm/developers.html#keeping-files-out-of-your-package
摘抄如下:
Use a .npmignore file to keep stuff out of your package. If there’s no .npmignore file, but there is a .gitignore file, then npm will ignore the stuff matched by the .gitignore file. If you want to include something that is excluded by your .gitignore file, you can create an empty .npmignore file to override it. Like git, npm looks for .npmignore and .gitignore files in all subdirectories of your package, not only the root directory.
.npmignore files follow the same pattern rules as .gitignore files:
Blank lines or lines starting with # are ignored.
Standard glob patterns work.
You can end patterns with a forward slash / to specify a directory.
You can negate a pattern by starting it with an exclamation point !.
By default, the following paths and files are ignored, so there’s no need to add them to .npmignore explicitly:.*.swp
._*
.DS_Store
.git
.hg
.npmrc
.lock-wscript
.svn
.wafpickle-*
config.gypi
CVS
npm-debug.log
Additionally, everything in node_modules is ignored, except for bundled dependencies. npm automatically handles this for you, so don’t bother adding node_modules to .npmignore.The following paths and files are never ignored, so adding them to .npmignore is pointless:
package.json README (and its variants) CHANGELOG (and its variants) LICENSE / LICENCE
If, given the structure of your project, you find .npmignore to be a maintenance headache, you might instead try populating the files property of package.json, which is an array of file or directory names that should be included in your package. Sometimes a whitelist is easier to manage than a blacklist.Testing whether your .npmignore or files config works§
If you want to double check that your package will include only the files you intend it to when published, you can run the npm pack command locally which will generate a tarball in the working directory, the same way it does for publishing.
因为要用到server.https 参考: https://nuxtjs.org/api/configuration-server/#example-using-https-configuration。
添加到nuxt.config.js中:
import path from 'path' import fs from 'fs' export default { server: { https: { key: fs.readFileSync(path.resolve(__dirname, 'server.key')), cert: fs.readFileSync(path.resolve(__dirname, 'server.crt')) } } }
就是读取ssl的两个文件。
一会Dockerfile 中把数据卷给加载到node.js容器内部,然后读取地址设置为内部地址即可。
虽然用node.js可以不必用nginx ,不过nginx在静态资源处理等方面依然有巨大优势,所以,要搞一个。
执行
docker-compose -f docker-compose.prod.yml build frontapp
Building frontapp
Step 1/7 : FROM node:14.5.0-alpine3.11
---> 5d97b3d11dc1
Step 2/7 : RUN mkdir -p /app
---> Running in f234d4093ee1
Removing intermediate container f234d4093ee1
---> 7cb78691eb3d
Step 3/7 : RUN apk update && apk upgrade && apk add --no-cache bash bash-doc bash-completion && /bin/bash && apk add --no-cache busybox && rm -rf /var/cache/apk/*
---> Running in ab1500e3b865
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
v3.11.6-93-ga95c3541d2 [http://dl-cdn.alpinelinux.org/alpine/v3.11/main]
v3.11.6-96-gc0aa9d3d49 [http://dl-cdn.alpinelinux.org/alpine/v3.11/community]
OK: 11271 distinct packages available
(1/1) Upgrading ca-certificates-cacert (20191127-r1 -> 20191127-r2)
OK: 7 MiB in 16 packages
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/7) Installing ncurses-terminfo-base (6.1_p20200118-r4)
(2/7) Installing ncurses-libs (6.1_p20200118-r4)
(3/7) Installing readline (8.0.1-r0)
(4/7) Installing bash (5.0.11-r1)
Executing bash-5.0.11-r1.post-install
(5/7) Installing pkgconf (1.6.3-r0)
(6/7) Installing bash-completion (2.9-r0)
(7/7) Installing bash-doc (5.0.11-r1)
Executing busybox-1.31.1-r9.trigger
OK: 14 MiB in 23 packages
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
OK: 14 MiB in 23 packages
Removing intermediate container ab1500e3b865
---> 26b6acc1f3a2
Step 4/7 : WORKDIR /app
---> Running in f9621319f198
Removing intermediate container f9621319f198
---> 945127e87a82
Step 5/7 : ENV NODE_ENV=production
---> Running in 08ac3f2d6a51
Removing intermediate container 08ac3f2d6a51
---> d8d659006939
Step 6/7 : RUN npm install
---> Running in 2146a3e2fd52
npm WARN saveError ENOENT: no such file or directory, open '/app/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/app/package.json'
npm WARN app No description
npm WARN app No repository field.
npm WARN app No README data
npm WARN app No license field.
up to date in 0.34s
found 0 vulnerabilities
Removing intermediate container 2146a3e2fd52
---> 5fe1126cc301
Step 7/7 : ENTRYPOINT [ "npm","start" ]
---> Running in 8a6ce295258a
Removing intermediate container 8a6ce295258a
---> 9eebc3bb8cb1
上面出错是因为 node的Dockerfile在install的时候并未把四大文件【.nuxt, static, package.json, nuxt.config.js】【见文末,是五个文件夹或文件,还有个node_modules】加载到node容器。
下面就是出错的Dockerfile代码
#使用node:14.5.0-alpine3.11 作为基础进行构建
FROM node:14.5.0-alpine3.11
#创建/app 目录作为部署目录,创建容器实例时,挂载此目录
RUN mkdir -p /app
#安装 bash 和 busybox
RUN apk update \
&& apk upgrade \
&& apk add --no-cache bash \
bash-doc \
bash-completion \
&& /bin/bash \
&& apk add --no-cache busybox \
&& rm -rf /var/cache/apk/*
#移动工作目录到 /app
WORKDIR /app
#设置node环境变量为production
ENV NODE_ENV=production
RUN npm install
#设置容器启动时执行的命令
ENTRYPOINT [ "npm","start" ]
添加
COPY ../../ssr-components/ /app
因为COPY 后面是外部文件夹,会报异常:
Service 'frontapp' failed to build: COPY failed: Forbidden path outside the build context: ../../ssr-components/ ()
原因是因为docker-compose.prod.yml中对frontapp build的context设置了固定
所以注释掉context 【context不能缺省】,
那么把ssr-components文件夹迁移到frontapp对应的Dockerfile文件夹下
然后再切换到存放docker-compose.prod.yml文件夹内执行
docker-compose -f docker-compose.prod.yml build frontapp
成功build
但是运行就报错
检查docker-compose配置文件frontapp部分:
volumes:
- ~/***client/ssr-components:/app
volume使用了~路径 所以加载不进去。
再把刚刚迁移到到frontapp对应的Dockerfile文件夹下的ssr-components文件夹迁移到本docker-composer文件对应文件夹下面的***client文件夹内,再修改volumes:
最好还是在Dockerfile里直接配置这个VOLUME
#使用node:14.5.0-alpine3.11 作为基础进行构建
FROM node:14.5.0-alpine3.11
#创建/app 目录作为部署目录,创建容器实例时,挂载此目录
RUN mkdir -p /app
COPY ./ssr-components/ /app
VOLUME ./ssr-components/ /app
#安装 bash 和 busybox
RUN apk update \
&& apk upgrade \
&& apk add --no-cache bash \
bash-doc \
bash-completion \
&& /bin/bash \
&& apk add --no-cache busybox \
&& rm -rf /var/cache/apk/*
#移动工作目录到 /app
WORKDIR /app
#设置node环境变量为production
ENV NODE_ENV=production
RUN npm install
#设置容器启动时执行的命令
ENTRYPOINT [ "npm","start" ]
至此,错误变成了:
参考 https://stackoverflow.com/questions/50355263/local-package-json-exists-but-node-modules-missing
及
https://www.cnblogs.com/cczlovexw/p/12916310.html
又在Dockerfile中添加了:
RUN npm run build RUN npm cache clean --force
错误又出:
此时发现了真正的原因,参考 https://hoody.tech/blog/detail/27 两种方法 我其实采用的是第一种,本地build后传文件到服务器。
发布目录所需文件
将以下文件拷贝至服务器目录
/app下的
.nuxt 编译后生成的目录,开发模式和发布模式通用,注意发布前使用
npm run build
防止将dev目录发布static 静态资源文件,通过
/
可直接访问package.json npm 包管理配置文件
nuxt.config.js Nuxt.js 默认的配置涵盖了大部分使用情形,可通过 nuxt.config.js 来覆盖默认的配置。
node_modules 依赖模块
没有node_modules
然后使用rsync传到ssr-components文件夹内
rsync.exe -e /usr/bin/ssh.exe -avzh "/cygdrive/d/nuxt/***client/node_modules" ****@95.179.242.118:~/***client/dockfiles/node/ssr-components
注:生成后有一个问题发现,在npm build生成时其实就已经提示过了:
其实就是
target替换成文本链接就不会报错。
原因是process.env….解析不了。
参考 https://github.com/nuxt-community/proxy-module/issues/3
摘:
process.env reads the environment variables.
You can use this to add some env variables for your project easily:
https://www.npmjs.com/package/dotenvI believe that adding an file ".env" with your api url and adding
"require('dotenv').config()" on the top of your nuxt config should do the
trick当然,官方也有说:https://nuxtjs.org/api/configuration-env/
所以解决办法是:
执行
npm install --save-dev @nuxtjs/dotenv安装@nuxtjs/dovenv
在nuxt.config.js顶部:
require('dotenv').config();然后在modules内添加
问题解决,然后执行npm build生成。
问题不断,在单独开启一个node docker执行 npm update 及npm install之后,【已经把那五个文件夹及文件给上传了】执行npm start给爷报错:
FATAL Enable vuex store by creating store/index.js.
然后搜了搜:
参考https://segmentfault.com/q/1010000019532412/a-1020000019666338:
将项目文件夹store,在package.json 文件中添加 "scripts"{"prostart": "nuxt start",},发布到服务器,用添加的命令启动
上传package.json文件,
启动node容器,进入容器内发现:
*****@laravel-docker-*****:~/***api/****-api$ docker exec -it ****-api_frontapp_run_2bb938841390 sh
/app # ls
node_modules nuxt.config.js package.json static
/app # cd /root
~ # ls
怎么只有四个文件 少了一个.nuxt文件夹
执行ls -la发现存在的:
docker-compose确实指定了卷。
frontapp: image: node:12-alpine container_name: ******frontapp restart: unless-stopped working_dir: /app environment: - NODE_ENV=production volumes: - ./*****/ssr-components:/app networks: - *****
执行
npm run prostart
错误依然。
贴上log
/app # cat /root/.npm/_logs/2020-07-18T07_26_50_279Z-debug.log 0 info it worked if it ends with ok 1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'run', 'prostart' ] 2 info using npm@6.14.5 3 info using node@v12.18.2 4 verbose run-script [ 'preprostart', 'prostart', 'postprostart' ] 5 info lifecycle ***client@1.0.0~preprostart: ***client@1.0.0 6 info lifecycle ***client@1.0.0~prostart: ***client@1.0.0 7 verbose lifecycle ***client@1.0.0~prostart: unsafe-perm in lifecycle true 8 verbose lifecycle ***client@1.0.0~prostart: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 9 verbose lifecycle ***client@1.0.0~prostart: CWD: /app 10 silly lifecycle ***client@1.0.0~prostart: Args: [ '-c', 'nuxt start' ] 11 silly lifecycle ***client@1.0.0~prostart: Returned: code: 1 signal: null 12 info lifecycle ***client@1.0.0~prostart: Failed to exec prostart script 13 verbose stack Error: ***client@1.0.0 prostart: `nuxt start` 13 verbose stack Exit status 1 13 verbose stack at EventEmitter.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16) 13 verbose stack at EventEmitter.emit (events.js:315:20) 13 verbose stack at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14) 13 verbose stack at ChildProcess.emit (events.js:315:20) 13 verbose stack at maybeClose (internal/child_process.js:1021:16) 13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5) 14 verbose pkgid ***client@1.0.0 15 verbose cwd /app 16 verbose Linux 4.15.0-106-generic 17 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "prostart" 18 verbose node v12.18.2 19 verbose npm v6.14.5 20 error code ELIFECYCLE 21 error errno 1 22 error ***client@1.0.0 prostart: `nuxt start` 22 error Exit status 1 23 error Failed at the ***client@1.0.0 prostart script. 23 error This is probably not a problem with npm. There is likely additional logging output above. 24 verbose exit [ 1, true ]
接下来直接
rm –rf node_modules #删除掉【当然就会删除容器挂载卷的宿主机的node_modules文件夹】
然后 npm install安装再试。
查看package.json设置 有一个
"private": true,
据packageJsonSchema.json 附言:
"private": {
"type": "boolean",
"description": "If set to true, then npm will refuse to publish it."
},
如果你在你的package.json中设置了“private”:true,那么npm将拒绝发布它。 这是防止私人存储库意外发布的一种方法。
如果你希望包装某个包只能被发布到特定的一个registry中(比如,一个内部的registry),则可以使用下面的publishConfig字典来描述以在publish-time重写registry配置参数。
尝试设置为false,继续:
依然不行。
遂改为SPA模式。