How to debug vue.js SFC (Single file component) in vscode, with TypeScript and webpack 4? - vue.js

For the example, everything seems to be working with chrome debugger extension installed.
When I tried to use:
<script lang="ts">
the source map seems just mess up. Following the instructions here, I can debug in Chrome, but not in vscode anymore.

I used the version 3 vue-cli template with TypeScript in Vue.js Single-File-Components rather than the guide you have linked, but I had a similar problem.
The vue-cli v.3 template ends up outputting TypeScript components' sourcemaps into a '.' folder (but all under webpack://) while the JavaScript components' sourcemaps end up in a 'src' folder. This resulted in the default sourceMapPaths working for the JavaScript SFCs but not the TypeScript SFCs. Therefore, I could set breakpoints in Chrome debugger directly, but not in the original files in VSCode for TypeScript SFCs.
My solution was to correct the mapping via the sourceMapPathOverrides configuration (alternatively, it could be corrected by modifying the build process but this seemed like the simple approach).
In .vscode/launch.json, you can set the appropriate mappings. The config I used ended up looking similar to the following (but you may have to adjust based on your exact setup):
{
"type": "chrome",
"request": "launch",
"name": "ChromeDebug",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}",
"breakOnLoad": true,
"sourceMaps": true,
"disableNetworkCache": true,
"sourceMapPathOverrides": {
"webpack:///*": "${webRoot}/*",
"webpack:///./*": "${webRoot}/*",
"webpack:///src/*": "${webRoot}/src/*"
}
}
(The last sourceMapPathOverrides entry is probably redundant. Your link seems to be using a '.://' root output path rather than my 'webpack://' root and you may also need to adjust the webRoot path to wherever your source files are. Don't forget to change the url/port as well, if it differs from my example.)
...
And the following is probably not related to OP's issue, but may be helpful for someone with a similar problem:
When using TypeScript, ensure that you have "sourceMap": true in your tsconfig.json.
If using vue-cli v.3, you may also need to add a vue.config.js file in the project root, such as the following, to change the devtool value from the default:
module.exports = { configureWebpack: { devtool: "source-map" } };

Related

Vue.js 3 extension breaks while using "vue-cli-service build" due to unsafe-eval

I am developing a chrome extension using vue 3, vue-router and vuex based on Kocal's project which uses vue-cli under the hood. I used whenever possible Single File Components with extensive use of vue bindings.
Everything works perfect on development mode but I recently tried to build the application for production and I encountered this error with partial rendering:
chunk-vendors.f6de00a6.js:11 EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
After a few days of digging, my understanding is that either webpack or vue compiling system is messing with CSP by referring/injecting code through eval scripts. As I am fairly new to this, it's hard for me to read to distinguish what I can do.
I tried different approaches:
defining $vue alias to a runtime only build in vue.config.js (supposedly removing unsafe eval by having code compiled before runtime but ending with a new error: Uncaught TypeError: Object(...) is not a function for o=Object(n["withScopeId"])("data-v-21ae70c6");)
using render() function at root
adding "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", to manifest.json
switching a component to render() to see if I have better chance with the partial rendering, but ending up with nothing being displayed although having console.log from render being executed.
Adding a config to chainWebpack splitting manifest and inline manifest on vue.config
What puzzles me is that I can't shake off the unsafe-eval, with at best a partial display, at worst a blank page. Bindings seem to be shaken off regardless and using a router-link to change page will give a blank page.
Edit: After digging through compiled code from webpack and setting minimize opt to false, it seems the error comes from a vendor: vue-i18n
The eval is likely coming from Webpack, due to an issue with global scoping.
see link for more detail https://mathiasbynens.be/notes/globalthis
Could you try adding this configuration to vue.config.js
module.exports = {
configureWebpack: {
node: {
global: false
},
plugins: [
new webpack.DefinePlugin({
global: "window"
})
]
}
};
tl;dr: Check your dependencies/packages, including those you wouldn't think they use unsafe-eval.
After digging into webpack internals and components building for vue3, here are the takeaways:
using Single File Components and default vue-cli config is ok as it will indeed just need vue runtime, so no unsolicited unsafe-eval
webpack config as below works:
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
global: "window" // Placeholder for global used in any node_modules
})
]
},
...
};
// Note that this plugin definition would break if you are using "unit-mocha" module for vue-cli
In the end, the issue was a dependency I was using for i18n vue-i18n#next, after removing it and switching to chrome's i18n way, it's now working.

polymer-cli - getting "Can’t find variable: babelHelpers" when I set compile to true

I use Polymer 2.0 and my build setting is:
"builds": [
{
"name": "bundled",
"bundle": true,
"js": { "compile": true},
"css": { "minify": true },
"html": { "minify": true }
}]
I get "Can’t find variable: babelHelpers" error after build.
The Polymer CLI version that I use is 1.1.0.
EDIT: I was using polymer-cli locally. After installing latest polymer-cli globally, now I get “Constructor requires ‘new’ operator” on safari and “Failed to construct ‘HTMLElement’: Please use the ‘new’ operator, this DOM object constructor cannot be called as a function.” on chrome.
EDIT2: used webcomponents-loader.js instead of webcomponents-lite.js and my problem solved.
I was getting same error. Problem was that index.html is technically my entrypoint in my polymer.json config, but my actual served up entrypoint is another file that comes from my server (_Layout.cshtml since I'm using .NET on my backend). What I needed to do was take the code in my compiled index.html file and move it over to my CSHTML file once I set "compile": true. Problem solved.

Unable to use Aurelia plugin

I'm trying to move one of my custom elements into a plug-in so that I can re-use it across projects.
I had a look at the skeleton plugin and noticed that it has a src/index.js that returns a config with all custom elements defined as globalResources.
So I tried the same thing and I basically have:
src/index.js
export function configure (config) {
config.globalResources([
'./google-map',
'./google-map-location-picker',
'./google-map-autocomplete'
]);
}
And then I have each one of my custom elements next to index.js, for example:
google-map.js
import {inject, bindable, bindingMode, inlineView} from 'aurelia-framework';
#inlineView(`
<template>
<div class="google-map"></div>
</template>
`)
#inject(Element)
export class GoogleMapCustomElement {
// All the Custom Element code here
}
I've also set up a basic npm script that runs babel on the code and sticks it in dist/:
"main": "dist/index.js",
"babel": {
"sourceMap": true,
"moduleIds": false,
"comments": false,
"compact": false,
"code": true,
"presets": [ "es2015-loose", "stage-1"],
"plugins": [
"syntax-flow",
"transform-decorators-legacy",
"transform-flow-strip-types"
]
},
"scripts": {
"build": "babel src -d dist"
},
Tbh I'm not entirely sure this is all correct but I took some of it from the skeleton plugin and it seems to run fine.
Anyway, the problem I'm having is that after I install the plugin (npm install --save-dev powerbuoy/AureliaGoogleMaps), add it to my aurelia.json in build.bundles[vendor-bundle.js].dependencies and tell aurelia to use it in main.js (.use.plugin('aurelia-google-maps')) I get:
GET http://localhost:9000/node_modules/aurelia-google-maps/dist/index/google-map.js (404)
So my question is, where does it get the dist/index/ part from?? I'm configuring my globalResources in index.js but nowhere does it say that I have an index folder.
What am I doing wrong?
Bonus question: What is the bare minimum required to transpile my ES6 plug-in code so that others can use it? Does my babel configuration look correct?
What about referencing your plugin within aurelia.json, like this:
{
"name": "aurelia-google-maps",
"path": "../node_modules/aurelia-google-maps/dist",
"main": "index"
}
I have absolutely no idea why, but in order to solve this problem I actually had to move my custom elements inside an index/ folder.
So now I have this:
- index.js
- index/
- custom-element-one.js
- custom-element-two.js
And my index.js still looks like this:
export function configure (config) {
config.globalResources([
'./custom-element-one',
'./custom-element-two'
]);
}
Where it gets index/ from I guess I will never know, but this works at least.
I did need the babel plug-in Marton mentioned too, but that alone did not solve the mystery of the made up path.
Edit: To elaborate a bit further, if I name my main entry point something other than index.js the folder too needs that name. For example, if I were to rename index.js main.js I would need to put my globalResources inside a folder called main/.
Update:
Edit: thanks for clarifying why you don't want to use the whole skeleton-plugin package.
Focusing on your original question: aurelia-cli uses RequireJS (AMD format) to load dependencies. Probably, your current output has a different format.
Add transform-es2015-modules-amd to babel.plugins to ensure AMD-style output, so it will be compatible with RequireJS and therefore with aurelia-cli.
"babel": {
"sourceMap": true,
"moduleIds": false,
"comments": false,
"compact": false,
"code": true,
"presets": [ "es2015-loose", "stage-1"],
"plugins": [
"syntax-flow",
"transform-decorators-legacy",
"transform-flow-strip-types",
"transform-es2015-modules-amd"
]
}
Original:
There are several blog post about plugin creation, I started with this: http://patrickwalters.net/making-out-first-plugin/ .
Of course, there have been many changes since then, but it's a useful piece of information and most of it still applies.
I'd recommend using plugin-skeleton as project structure. It provides you with a working set of gulp, babel, multiple output formats out-of-the-box.
With this approach, your plugin's availability wouldn't be limited to JSPM or CLI only but everyone would have the possibility to install it regardless of their build systems.
Migration is fairly easy in your case:
Download skeleton-plugin
Copy your classes + index.js into src/
npm install
...wait for it...
gulp build
check dist/ folder
most of your pain should now be gone :)
Here are some details based on my observations/experience.
1. Main index.js/plugin-name.js:
In general, a main/entry point is required, where the plugin's configure() method is placed. It serves as a starting point when using it within an Aurelia application. This file could have any name, usually it's index.js or plugin-name.js (e.g. aurelia-google-maps.js) to make it clear for other developers what should be included for bundling. Set that same entry point in package.json as well.
In addition to globalResources, you can implement a callback function to allow configuration overrides. That can be called in the application, which will use the plugin. Example solution
Plugin's index.js
export * from './some-element';
export function configure(config, callback) {
// default apiKey
let pluginConfig = Container.instance.get(CustomConfigClass);
pluginConfig.apiKey = '01010101';
// here comes an override
if (callback) {
callback(pluginConfig);
}
...
config.globalResources(
'./some-element'
);
}
Your app's main.js
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin('aurelia-google-maps', (pluginConfig) => {
// custom apiKey
pluginConfig.apiKey = '12345678';
});
aurelia.start().then(a => a.setRoot());
}
2. HTML and CSS resources:
If you have html only custom elements, you can make them available using globalResources.
Custom css styling is going to require a bit of additional configuration in bundling configuration (see below).
3. Using the plugin with aurelia-cli: Documentation
One of the first new features you'll see soon is a command to help you with 3rd party module configuration. The command will inspect a previously npm-installed package, and make a configuration recommendation to you, automating the process if you desire.
While we are looking forward to that above moment, let's edit aurelia.json:
Configure plugin dependencies. If there are any external libraries (e.g. Bootstrap), then those should be included before your plugin.
Include your plugin:
...
{
"name": "plugin-name",
"path": "../node_modules/plugin-name/dist/amd",
"main": "plugin-name",
"resources": ["**/*.html", "**/*.css"] // if there is any
},
...
Now, your plugin is ready to include it in main.js as showed in Section 1..
I hope you didn't get sick of reading the word 'plugin' so many (21!) times. :D

What steps need to be taken to get autocomplete working for React Native in Visual Studio Code?

I have followed the steps outlined in the VS Code documentation for getting Intellisense working for React Native by installing typings for React Native. Now, what do I need to do to get autocomplete working? For instance, if I type <Text>, I would like to see an automatic closing of that tag. What am I missing here? This seems like it shuld work out of the box.
To enable IntelliSense (autocomplete) you have to install the official React Native Tools extension.
Installation
Open Command Palette by pressing F1, type ext install and press Enter, then look for React Native Tools extension.
Create a jsconfig.json file
You should create a jsconfig.json file in you root directory. It can be empty but must be present. The presence of such a file in a directory indicates that the directory is the root of a JavaScript project.
(Optional)
The file itself can optionally list the files belonging to the project, the files to be excluded from the project, as well as compiler options.
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules"
]
}
You can find more at https://code.visualstudio.com/docs/languages/javascript#_javascript-projects-jsconfigjson
Create a .babelrc file for ReactNative Packger transformer (optional, if you want to use TypeScript)
You should create a .babelrc file with sourceMaps = true and "presets": [ "react-native" ] for better source-mapping support. (required if you want TypeScript support).
{
"presets": [
"react-native" // this is required for debugging with react-native/packager/transformer
],
"plugins": [],
"sourceMaps": true // must be true react-native/packager/transformer using with node-module-debug
// because of some bugs from vscode-node-debug & vscode-react-native, "sourceMaps" cannot be "inline" or "both"
}
Install typings for React Native (optional)
To get IntelliSense for React Native, run npm install typings -g and then typings install dt~react-native --global in your terminal.
Hope this helps!!
React Native Tools in VSCode can't help you close the Tag after you typed<Text>,you can try to install Auto Close Tag and Auto Rename Tag
In my case, I have to copy jsconfig.json to tsconfig.json, close Visual Code and reopen it. Then it works properly.
jsconfig.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules"
]
}
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules"
]
}
I am also not getting any IntelliSense and also package auto-import is not working. Since I am not using Typescript, deleting the tsconfig.json helped me.
Take backup of your tsconfig.json file first
In my case, I've already installed many react-native extensions for autoSuggestion and another helper extension, e.g. "React Native Tools", and "React-Native/React/Redux snippets for es6/es7"
Issues:
autoSuggestion keywords not coming while typing.
command(in IOS) + click not letting me to jump on the target files.
Recently I have seen in VS Code editor for new React-native applications autoSuggestion not working.
Steps I have followed to solve:
Go to Extensions
Search for React or React-native
Remove the installed extension
Reload it.

Create different versions form one bootstrap file with require.js

I develop an iPad/iPhone App web app. Both share some of the resources. Now I wanna build a bootstrap js that looks like this:
requirejs(['app'], function(app) {
app.start();
});
The app resource should be ipadApp.js or iphoneApp.js. So I create the following build file for the optimizer:
{
"appDir": "../develop",
"baseUrl": "./javascripts",
"dir": "../public",
"modules": [
{
"name": "bootstrap",
"out": "bootstrap-ipad.js",
"override": {
"paths": {
"app": "ipadApp"
}
}
},
{
"name": "bootstrap",
"out": "bootstrap-iphone.js",
"override": {
"paths": {
"app": "iphoneApp"
}
}
}
]
}
But this doesn't seems to work. It works with just one module but not with the same module with different outputs.
The only other solution that came in my mind was 4 build files which seems a bit odd. So is there a solution where i only need one build file?
AFAIK the r.js optimizer can only output a module with a given name once - in your case you are attempting to generate the module named bootstrap twice. The author of require.js, #jrburke made the following comment on a related issue here:
...right now you would need to generate a separate build command for each script being targeted, since the name property would always be "almond.js" for each one.
He also suggests:
...if you wanted just one build file to run, you could create a node program and drive the optimizer multiple times in one script file. This example shows using requirejs as a module and calling requirejs.optimize().
I took a similar approach in one of my projects - I made my build.js file an ERB template and created a Thor task that ran through my modules and ran r.js once for each one. But #jrburke's solution using node.js is cleaner.