Webpack compiling ES6 into module - ecmascript-6

I am trying to compile ES6 to a file using Webpack and can't figure out why the code is not usable as it is.
Side note : This is meant to be a plugin for VueJS
I start with a simple file that exports a single function such as
exports.install = () => {
...
}
Webpack uses babel-loader and babel-preset-es2015 to compile it.
You may find webpack config, source and compiled files in this gist.
My problem is the result is not "requirable" in my Vue app... It has some weird stuff around the core needed exports.install statement. When I remove all this stuff and leave just exports.install = ... it is OK, otherwise I just don't get anything out of it.
I am using it in another app built with webpack, through an import statement.

Without an output.libraryTarget option, webpack will generate a bundle you can include via a <script> tag, but not import. I think this is what you're seeing.
If you want to import (or require) the result of your webpack build, you should set libraryTarget to commonjs2
output: {
filename: 'index.js',
libraryTarget: "commonjs2"
},
With this libraryTarget configuration, the webpack output will look like module.exports = /* ... the "weird stuff" */, so when you import it, you'll get the exported function you expect.
If all you're doing is compiling a single file or set of files that will be imported in another webpack build, you might consider not using webpack at all, and instead using the Babel CLI directly. In your Gist, you're not getting anything from webpack other than wrapping your module in some extra webpack bootstrap code.

Related

I want to load an html version of my resume for my website. But its failing to compile

import ResumeHTML from "resume.html"
const ReactComponent = () => {
return (<a href={ResumeHTML}>View Resume</a>)
}
Failed to compile
./src/assets/resume.html 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
The error happens because Webpack does not know how to handle import of .html files inside your javascript module.
If you have a webpack configuration in your project you can add a loader for html files, probably the file-loader that copies your file in the public directory and replace it with a link inside your javascript module.
If you do not have access to your webpack configuration (ex. if you're using a non ejected version of Create React App), you should instead make your html file public and hardcode the link in your javascript module without importing the file.

Loading JSON files in React, without JSON extension

I'm trying to require some JSON files in my React app (based on CRA 3.01 with Typescript).
The normal const obj = require('./path/file.json') would work if my files had a .json extension - however, these files have .md for 'metadata' and a couple other extensions, and the standard require isn't working. The files are from a tool, so changing to .json isn't a practical option.
Doing some research, it seems the approach is to use the webpack json-loader module (the webpack json-loader docs says that working with different file extensions is the main reason for using the module). I found an example and am using this:
const context = require.context(
"json-loader!./metadata",
true,
/^\.\/.*\.md$/
);
const metadata = context("./foo.md");
I've got a minimum reproduction here (see App.tsx):
https://github.com/ericsolberg/testjson
It seems that this is correctly using the json-loader, and finding the file correctly. However, I'm getting a syntax error:
Error: Module build failed (from ./node_modules/json-loader/index.js):
SyntaxError: Unexpected token m in JSON at position 0
at JSON.parse (<anonymous>)
at Object.module.exports (/Users/***/projects/jsontest/node_modules/json-loader/index.js:4:49)
I did some research on this error, and believe the problem is that the file is being parsed twice - first by the loader configured by CreateCreactApp's default webpack config, then by the specified JSON loader.
I don't want to eject my CRA app to modify the webpack config, and would like to avoid a re-wire hack (and whatever other issues that introduces) ... does anyone know of a way to load JSON files in a CRA app, if these files don't have a JSON extension?
Here's the solution that ended up working for me.
I could eject my project, of course, and customize the webpack config to load JSON files with other extensions. It may be possible to make a rewire hack work as well.
But I realized that when I require a file that is not one of the extensions recognized by CRA's config, it instead copies that file into the build, and require('file.ext') returns the URL of the file. So I'm using axios to load the file. This means a trip to the server for something that could be done statically, but for where I'm taking this project that is actually OK (eventually it will load metadata from a server anyway).

How to import package.json in TypeScript?

I'm trying to import my package.json file in TypeScript and it doesn't seem to work. Specifically, I'm just trying to import it so that I can access the name and version properties for a log statement. Something like:
import * as pjson from '../package.json';
// other code here
log.info(`${pjson.name}:${pjson.version}` started on port ...);
We have this same syntax elsewhere in other projects that use Node/Babel, but I'm trying to introduce some TypeScript around these parts. Elsewhere we'd do something like:
import { name, version} from '../package.json';
That doesn't work here however. I followed the instructions at https://www.npmjs.com/package/json-d-ts which at least made the error on my import statement go away, but now when I try to access properties I get the following error:
src/index.ts(20,21): error TS2339: Property 'name' does not exist on type 'typeof import("*.json")'.
src/index.ts(20,35): error TS2339: Property 'version' does not exist on type 'typeof import("*.json")'.
Is there a way to fix this, or do I just have to hardcode these values somewhere (rather than dynamically retrieving them from package.json)? Maybe I can declare a type for import("*.json") somehow with these properties defined on it?
How to import *.json ?
As already answered you need Typescript >= 2.9 and the following settings in tsconfig.json:
{
"resolveJsonModule": true,
"esModuleInterop": true,
"module": "commonjs"
}
But there are restrictions:
You must compile to CommonJS
All your imported JSONs must reside under the "rootDir"
Unfortunately the "rootDir" is very often a folder beneath package.json like './src' and things would fail.
So:
How to import package.json ?
You can require it:
const pjson = require('../package.json');
If you use npm.start: you don't need to :
The package.json fields are tacked onto the npm_package_ prefix. So, for instance, if you had {"name":"foo", "version":"1.2.5"} in your package.json file, then your package scripts would have the npm_package_name environment variable set to “foo”, and the npm_package_version set to “1.2.5”. You can access these variables in your code with process.env.npm_package_name and process.env.npm_package_version, and so on for other fields.
npm exports package.json attributes as env vars with the the prefix npm_package_ as described in npm docs
So if you're using npm you can get the version as process.env.npm_package_version
Since TypeScript 2.9 you can import JSON files as described here:
typescriptlang documentation 2.9#json, for this you need to enable the "resolveJsonModule" option in your tsconfig.json.
You need typescript version 2.9 in your project:
npm i typescript#latest --save or yarn add typescript
if you are building the typescript files from the command line with tsc, you will need to install the latest typescript version globally:
npm i -g typescript#latest or yarn global add typescript
if you are building your project with webpack and webpack-dev-server you need to make sure that json files are hosted in the webpack-dev-server context as static files. And even if you hosted them, you can't import json files in the web environment like this, you would need to load the json file with an ajax request and parse the response with JSON.parse.
Ensure tsconfig.json compiler options contains:
"resolveJsonModule": true,
"esModuleInterop": true,
"module": "commonjs"
Import package.json with typings
import * as pack from '../package.json';
Typescript should be able to do it as follows:
import * as pack from "../package.json"
// access name and version like this:
console.log(pack.name);
Check out the third grey box under Support for well-typed JSON imports.
https://blogs.msdn.microsoft.com/typescript/2018/05/31/announcing-typescript-2-9/#json-imports

How to deploy a raw JSON file that Webpack 4 treats as a split module?

I don't think this is an uncommon problem, but it seems like the keywords turn up many false positives. I've tried searching for "webpack dynamic configuration file", "webpack runtime load JSON file", and more. I see many results for configuring Webpack dynamically, but not many for configuring a bundled app dynamically.
I want to have a configuration file that sits in my deployment as raw JSON, i.e. no Webpack runtime or module boilerplate. Just a valid JSON file.
I want to "import" that JSON configuration in my code as I would as if it were a module, i.e. like this:
import config from './config.json'
I want Webpack to omit the JSON file from the bundle, but insert any necessary code to asynchronously request and inject the config.json waiting on the server.
I want Webpack to ignore whether ./config.json exists at build time, and to just optimistically assume it will be in the right place at runtime.
I'd love if I could specify that './config.json' is a module alias, and for Webpack to copy the aliased file to the correct location (with name config.json) in the build directory.
This will give me a raw JSON file in my deployment that my site administrator can edit without running Webpack. It lets me as a developer code as if config.json is a regular module. How can I do this? I've seen suggestions to use
externals: {
'./config.json': "require('./config.prod.json')",
},
but that won't work in the browser, where require does not exist.
I've tried this configuration with no luck. The JSON is still inlined into the bundle:
resolve: {
alias: {
'./config.json': path.resolve(__dirname, 'src/config.prod.json')
}
},
optimization: {
splitChunks: {
cacheGroups: {
config: {
test: './config.json',
chunks: 'all',
name: 'config',
priority: 100
}
}
}
}
I am using Webpack 4.
In short, you can't use
import config from './config.json'
At least not if this should run in the browser.
webpack externals would make this possible for a nodejs application.
What you really want is a normal http call.
Just get the config.json file with something like fetch.
fetch('url/config.json')
You can use copy-webpack-plugin to put the config in the correct place when webpack compiles (but do you want that if there are changes directly to this file on the server)

SublimeText: transpile ES6 to ES5 on save

With the Less plugin I got a nice Less -> Css compilation whenever I save the file. How to get the same behavior with Babel to have ES6 code transpiled to ES5? Thanks
Edited after #lukas-kabrt suggestion:
The less2css Sublime plugin, utilizes the on_post_save() event of the Sublime API, to listen for a file Save and then trigger the code that will compile the .less file automatically. Something similar can be accomplished for Babel ES6-to-ES5 compilation, by using this event in a plugin, and linking it to an external command that will auto compile the current file using Babel. This is a simple plugin for ST2, written in Python, that accomplishes this:
import sublime, sublime_plugin,os
from os.path import dirname, realpath
class BuildonSave(sublime_plugin.EventListener):
def on_post_save(self, view):
es6File = view.file_name()
filename, file_extension = os.path.splitext(es6File)
if file_extension == ".es6":
view.window().run_command('exec',{'cmd': ["/usr/local/bin/babel", es6File, "-o", filename+".js", "--source-maps", "inline"] })
Note: This plugin looks for .es6 suffixed files and compiles them to the appropriate .js file, e.g. myfile.es6, will be transpiled into an ES5 myfile.js file.
The cmd location /usr/local/bin/babel can be obtained on your system by running the which babel command on the terminal, if you're on Mac OS X.
Source code can also be found here: https://gist.github.com/kostasx/1d55c62edcee88375fc8
You can checkout the Sublime Plugin API documentation, if you want to mingle with the code above a little more.