Project details: A Todo
application with / app
`(main page) and / login
(login page) two routes
when rendering ssr
, I used routing lazy loading , and then packaged the front-end code with webpack, I packaged
successfully, and then there was an error accessing the main page when starting the server port (but there is no problem with the generation environment
, production environment debugging uses webpack-dev-server + koa to start two ports). The reason for the error in production environment access is:
TypeError: Cannot read property "call" of undefined
at r (webpack/bootstrap:39:0)
at Object.<anonymous> (client/views/todo/todo.vue?6149:6:0)
at r (webpack/bootstrap:39:0)
at Object.<anonymous> (client/views/todo/todo.vue?7847:6:0)
at r (webpack/bootstrap:39:0)
at VueComponent.s (client/views/todo/todo.vue:11:0)
at VueComponent.c (node_modules/vue-loader/lib/runtime/component-normalizer.js:65:0)
at callHook (D:\Editors\WebStorm\Files\20180423-imooc-vue-todo-further\node_modules\vue\dist\vue.runtime.common.js:2919:21)
at VueComponent.Vue._init (D:\Editors\WebStorm\Files\20180423-imooc-vue-todo-further\node_modules\vue\dist\vue.runtime.common.js:4624:5)
at new VueComponent (D:\Editors\WebStorm\Files\20180423-imooc-vue-todo-further\node_modules\vue\dist\vue.runtime.common.js:4796:12)
< H2 > preliminary inference of the cause of error < / H2 >
I Baidu a lot of answers, but are invalid, I suspect is component lazy loading error
, because Login component
lazy loading no problem, and Todo component
load is wrong, the difference between them is that Login component does not have sub-components
, and Todo also has sub-components
.
I am puzzled. I hope the bosses will answer.
< H2 > part of the code < / H2 > < hr > the following is the configuration of webpack packaging
:
webpack basic configuration baseConfig:
const baseConfig = {
mode: process.env.NODE_ENV || "production", // webpack 4
target: "web",
entry: {
app: path.join(__dirname, "../client/client-entry.js")
},
output: {
path: path.join(__dirname, "../public"),
filename: "bundle.[hash:8].js",
// devServerhistoryApiFallback
publicPath: "http://127.0.0.1:8080/public/"
},
module: {
rules: [
{
test: /\.(vue|jsx|js)$/,
loader: "eslint-loader",
exclude: /node_modules/,
enforce: "pre" /* loaderloader */
},
{
test: /\.vue$/,
loader: "vue-loader",
options: createVueLoaderOptions(isDev)
},
{
test: /\.jsx$/,
loader: "babel-loader"
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: "/node_modules/"
},
{
test: /\.(jpg|jpeg|png|svg|gif)$/,
use: [
{
loader: "url-loader",
options: {
limit: 1024,
name: "resources/[path][name].[hash:8].[ext]"
}
}
]
}
]
}
}
configuration in the build environment:
//
config = merge(baseConfig, {
mode: "production",
entry: {
app: path.join(__dirname, "../client/client-entry.js")
},
output: {
filename: "[name].[chunkhash:8].js",
publicPath: "/public/"
},
module: {
rules: [
{
test: /\.styl$/,
use: ExtractPlugin.extract({
/* style-loaderjshtml */
fallback: "style-loader",
use: [
"css-loader",
{
loader: "postcss-loader",
options: {
sourceMap: true
}
},
"stylus-loader"
]
})
}
]
},
plugins: defaultPlugins.concat(new ExtractPlugin("styles.[chunkhash].css")),
optimization: {
splitChunks: {
chunks: "all"
},
runtimeChunk: true
}
})
< hr >
the following is part of the code for routing lazy loading:
// /login/app
const Todo = () => import("../views/todo/todo.vue")
const Login = () => import("../views/login/login.vue")
// xxx
export default [
{
path: "/",
redirect: "/app"
},
{
path: "/app",
component: Todo,
name: "app",
},
{
path: "/login",
component: Login
}
]
if routing lazy loading is not used, after webpack is packaged, there will be no problem with production environment access.
//
import Todo from "../views/todo/todo.vue"
import Login from "../views/login/login.vue"
// xxx
export default [
{
path: "/",
redirect: "/app"
},
{
path: "/app",
component: Todo,
name: "app",
},
{
path: "/login",
component: Login
}
]
< hr >
paste the code of login.vue
and todo.vue
components separately:
login.vue:
<template>
<div>
</div>
</template>
<script>
export default {
metaInfo: {
title: "Login - Todo App"
}
}
</script>
todo.vue:
<template>
<section id="todo-wrapper" class="todo-wrapper">
<input
type="text"
class="add-input"
@keyup.enter="addTodo"
autofocus="autofocus"
placeholder=""
>
<Item
v-for="todo in filterTodos"
:todo="todo"
:key="todo.id"
@del="deleteTodo"
></Item>
<Tabs :todos="todos"
:filter="filter"
@changeFilter="changeFilter"
@clearCompleted="clearCompleted"></Tabs>
</section>
</template>
<script>
import Item from "./item.vue"
import Tabs from "./tabs.vue"
let id = 0
export default {
metaInfo: {
title: "The Todo App"
},
components: {
Item,
Tabs
},
props: ["id"],
data () {
return {
filter: "all",
todos: []
}
},
mounted () {
console.log(this.$route)
console.log("id: ", this.id)
},
computed: {
filterTodos () {
let state = this.filter
if (state === "all") {
return this.todos
} else if (state === "active") {
return this.todos.filter(todo => !todo.completed)
} else {
return this.todos.filter(todo => todo.completed)
}
}
},
methods: {
addTodo (e) {
this.todos.unshift({
id: idPP,
content: e.target.value.trim(),
completed: false
})
e.target.value = ""
},
deleteTodo (id) {
this.todos.splice(this.todos.findIndex(todo => todo.id === id), 1)
},
clearCompleted () {
this.todos = this.todos.filter(todo => !todo.completed)
},
changeFilter (state) {
this.filter = state
}
}
}
</script>
<style lang="stylus" scoped>
.todo-wrapper {
width 600px
margin 0 auto
padding 10px
box-shadow 0 0 5px -sharp666
background-color -sharpfff
}
.add-input {
position relative
width 100%
padding 16px
outline none
border none
font-size 24px
line-height 40px
box-shadow inset 0 -2px 1px rgba(0, 0, 0, 0.03)
}
</style>
Thank you.