Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

当传入的变量值为数字0时,变量消失 #39

Closed
KarnaughK opened this issue Jun 29, 2020 · 14 comments
Closed

当传入的变量值为数字0时,变量消失 #39

KarnaughK opened this issue Jun 29, 2020 · 14 comments
Assignees
Labels

Comments

@KarnaughK
Copy link

问题是什么

当传入的变量值为数字0时,变量消失,传1就有值

环境

webpack + "templatejs-loader": "^2.2.0" + "@templatejs/runtime": "^2.1.0"

其他

这算bug么

@yanhaijing
Copy link
Owner

能否贴点代码?

@KarnaughK
Copy link
Author

KarnaughK commented Jun 30, 2020

呃。。那我就贴个简写的代码吧:

// js

let userTpl = require("./tpl/index.tmpl");
let USER_INFO = {isExpired:0}
$("#userInfoTpl").html(
        userTpl(
            $.extend(USER_INFO, {
                // isExpired: USER_INFO.isExpired + "", // 如果值是数字0,那么tmpl会丢失这个变量(这是后来写的)
            })
        )
    )
<!--  index.tmpl -->

 if(isExpired != 0) {#>
   <p>一开始是被提了 bug,查了发现这个 if 判断结果一直是 true</p>
 <#}#>

<p>然后我就打印了一下发现没有打印出 0,而是空<#:=isExpired#></p>
// webpack.base.conf.js

module: {
        rules: [
            // eslint
            {
                test: /\.(js)$/,
                loader: "eslint-loader",
                enforce: "pre",
                include: [path.join(__dirname, "src")],
                options: {
                    fix: true
                }
            },
            // 处理js, 兼容处理到es5
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ["@babel/preset-env"],
                        plugins: [
                            "@babel/plugin-transform-runtime",
                            "@babel/plugin-transform-modules-commonjs"
                        ]
                    }
                }
            },
            // html处理
            {
                test: /\.html$/,
                use: [
                    {
                        loader: "html-loader",
                        options: {
                            minimize: true, // 压缩
                            attrs: ["img:src", "img:data-src", "audio:src"], // 处理html文件中的src引用
                            root: path.resolve(__dirname, "./dist")
                        }
                    }
                ]
            },
            // ejs模板处理
            {
                test: /\.ejs$/,
                use: ["ejs-loader?variable=data"]
            },
            // 字体处理
            {
                test: /\.(woff|woff2|eot|ttf|svg)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        // 保留原文件名和后缀名
                        name: "[name].[hash:7].[ext]",
                        // 输出到dist/fonts/目录
                        outputPath: "fonts"
                    }
                }
            },
            // htc文件处理
            {
                test: /\.(htc)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        // 保留原文件名和后缀名
                        name: "[name].[hash:7].[ext]",
                        // 输出到dist/static/目录
                        outputPath: "static"
                    }
                }
            },
            // templatejs处理
            {
                test: /\.tmpl/,
                loader: "templatejs-loader",
                options: {
                    sTag: "<#",
                    eTag: "#>",
                    escape: false,
                    expression: 'require("@templatejs/runtime").default'
                }
            },
            // 图片处理
            {
                test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
                loader: "url-loader",
                options: {
                    esModule: false, // 不使用es语法加载
                    limit: 1024, // 大小范围内使用base64
                    name: "[name].[hash:7].[ext]",
                    // publicPath: "./img",
                    outputPath: "img"
                }
            }
        ]
    },

@yanhaijing
Copy link
Owner

收到,我排查下 看起来很奇怪

@yanhaijing yanhaijing self-assigned this Jun 30, 2020
@yanhaijing yanhaijing added the bug label Jun 30, 2020
@yanhaijing
Copy link
Owner

我打算写个 create-template-app 这样就能快速搭建一个项目现场了o(╯□╰)o

@yanhaijing
Copy link
Owner

亲 我好像没能复现啊

我的 app.js

var tpl = require('./demo.tmpl');

var html = tpl({
    a: 0,
    isExpired: 0,
});

document.getElementById('test').innerHTML = html;

我的demo.tmpl

<# if(isExpired != 0) {#>
   <p>一开始是被提了 bug,查了发现这个 if 判断结果一直是 true</p>
 <#}#>

结果是好的,下面是build完的代码,可以看到isExpired 也就是u的判断都在的

    (function(t) {
        r.exports = function(r) {
            var n = e(3).default
              , o = "object" == typeof self && self.self === self && self || "object" == typeof t && t.global === t && t || this
              , u = r.isExpired || n.functionMap.isExpired || o.isExpired;
            try {
                var i = "";
                n.modifierMap;
                return i += "",
                0 != u && (i += "\n",
                i += "   <p>一开始是被提了 bug,查了发现这个 if 判断结果一直是 true</p>\n",
                i += " "),
                i
            } catch (r) {
                return r.name = "RenderError",
                r.tpl = "demo.tmpl",
                n.handelError(r),
                "template.js error"
            }
        }
    }
    ).call(this, e(2))

你是哪里搞的不对?我看你的代码里,if前面缺少一个 <#

<!--  index.tmpl -->

 if(isExpired != 0) {#>
   <p>一开始是被提了 bug,查了发现这个 if 判断结果一直是 true</p>
 <#}#>

<p>然后我就打印了一下发现没有打印出 0,而是空<#:=isExpired#></p>

@yanhaijing yanhaijing added question and removed bug labels Jun 30, 2020
@KarnaughK
Copy link
Author

代码肯定是没问题的啦,少 <# 是因为少复制了吧大概,我修完那个 bug 以后昨天在开发新功能的时候又遇到了这个问题,今天我又试了一下,0 和 false 都会导致值丢失,如果正常无法复现的话可能是和我项目里的其他东西配合时出了问题吧。。。

如果 create-template-app 弄好的话麻烦@我一下,我想试试如何复现😂

@KarnaughK
Copy link
Author

我看了一下编译出来的代码

// 您复现编译出来是:
u = r.isExpired || n.functionMap.isExpired || o.isExpired;

// 我复现编译出来是:
a = e["emailTime"] || r.functionMap["emailTime"] || i["emailTime"];

这个 emailTime 就是昨天我写代码时又遇到时的变量

@yanhaijing
Copy link
Owner

yanhaijing commented Jul 1, 2020

嗯我知道咋回事了,这个判断有问题啊。。。
e["emailTime"] 为0 或者徦值时 就会取||后面的。。。

a = e["emailTime"] || r.functionMap["emailTime"] || i["emailTime"]

应该这样判断。。。

a = "emailTime" in a ? e["emailTime"] : r.functionMap["emailTime"]

bug捉到了,我得发个版😳

@yanhaijing yanhaijing added bug and removed question labels Jul 1, 2020
@yanhaijing yanhaijing reopened this Jul 1, 2020
@yanhaijing
Copy link
Owner

嗯我知道咋回事了,这个判断有问题啊。。。
e["emailTime"] 为0 或者徦值时 就会取||后面的。。。

a = e["emailTime"] || r.functionMap["emailTime"] || i["emailTime"]

应该这样判断。。。

a = "emailTime" in a ? e["emailTime"] : r.functionMap["emailTime"]

bug捉到了,我得发个版😳

这两种方式都有一个问题,会访问到原型链上的属性

var a = {};

a.toString // 能获取到
'toString' in a // true

更好的方式是用hasOwnProperty判断

a = a.hasOwnProperty("emailTime" ) ? e["emailTime"] : r.functionMap["emailTime"]

@yanhaijing
Copy link
Owner

yanhaijing commented Jul 1, 2020

升级到 >= [email protected] 已修复这个问题
先按in的方式修复的,后面有时间改为 hasOwnProperty

@yanhaijing
Copy link
Owner

yanhaijing commented Jul 1, 2020

看着下只有2.x有这个问题,0.x没这个问题,不用修复
0.x的实现方式是遍历data

for(var key in data) {
        var magickey = data['key'] // magickey 是一个黑魔法,相当于 var [key] = data['key'] 
}
  1. 0.x版本的问题是会存在击穿模式,如果一个变量data中没有传入,就会访问到window上
  2. 2.x修复了这个问题
    • sandbox模式(沙盒)下,所有变量,即便data上没有传入,也不会访问到window上,更安全,但是用到系统api也需要注入,类似angular和vue
    • 出于兼容性考虑,非sanbox模式下,依然会访问到window上的变量
    • sandbox更安全

@yanhaijing
Copy link
Owner

TODO:后面改成hasOwnProperty,同时加了单元测试后,在关闭这个issue

@yanhaijing
Copy link
Owner

cli写好了,试试^_^

$ npx @templatejs/cli new myapp
# 选择对应的平台
# ❯ webpack4 
#   rollup 
#   parcel 
#   fis3 
#   browserify 
#   gulp 
#   browser 

@yanhaijing
Copy link
Owner

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants